Jak zrobić kopię pliku w Androidzie?

Odpowiedzi:

327

Aby skopiować plik i zapisać go na docelowej ścieżce, możesz użyć poniższej metody.

public static void copy(File src, File dst) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dst);
        try {
            // Transfer bytes from in to out
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
}

W API 19+ możesz używać automatycznego zarządzania zasobami Java:

public static void copy(File src, File dst) throws IOException {
    try (InputStream in = new FileInputStream(src)) {
        try (OutputStream out = new FileOutputStream(dst)) {
            // Transfer bytes from in to out
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        }
    }
}
Rakshi
źródło
8
Dziękuję Ci. po tym, jak uderzyłem się w głowę, okazało się, że problemem jest brak uprawnień do zapisu w pamięci zewnętrznej. teraz działa dobrze.
AS
8
@ mohitum007 jeśli plik nie zostanie skopiowany, zgłoszony zostanie wyjątek. użyj wywołania metody try catch.
Nima G
9
Jeśli zostanie zgłoszony wyjątek, strumienie nie zostaną zamknięte, dopóki nie zostaną usunięte, a to nie jest dobre . Rozważ zamknięcie ich finally.
Pang
1
@Ostry ból. Masz rację. Co gorsza, należy wywołać metodę in / out.close (), w przeciwnym razie nastąpi przeciek zasobów w podstawowym systemie operacyjnym, ponieważ GC nigdy nie zamknie otwartych deskryptorów plików. GC nie może zamykać zasobów systemu operacyjnego poza JVM, takich jak deskryptory plików lub gniazda. Muszą one zawsze być programowo zamknięte w klauzuli wreszcie lub użyj nowej składni try-with-resource: docs.oracle.com/javase/tutorial/essential/exceptions/…
earizon
4
Proszę zamknąć oba strumienie w końcu, jeśli istnieje wyjątek, pamięć strumieni nie zostanie zebrana.
pozuelog
121

Alternatywnie możesz użyć FileChannel, aby skopiować plik. To może być szybsze niż metoda kopiowania bajtów podczas kopiowania dużego pliku. Nie możesz go jednak użyć, jeśli Twój plik jest większy niż 2 GB.

public void copy(File src, File dst) throws IOException {
    FileInputStream inStream = new FileInputStream(src);
    FileOutputStream outStream = new FileOutputStream(dst);
    FileChannel inChannel = inStream.getChannel();
    FileChannel outChannel = outStream.getChannel();
    inChannel.transferTo(0, inChannel.size(), outChannel);
    inStream.close();
    outStream.close();
}
NullNoname
źródło
3
transferTo może zgłosić wyjątek, w którym to przypadku pozostawiasz otwarte strumienie. Tak jak Pang i Nima skomentowali w zaakceptowanej odpowiedzi.
Viktor Brešan
TransferTo powinien być również wywoływany wewnątrz pętli, ponieważ nie gwarantuje, że przekaże całkowitą żądaną kwotę.
Viktor Brešan
Wypróbowałem twoje rozwiązanie i dla mnie nie działa, z wyjątkiem java.io.FileNotFoundException: /sdcard/AppProj/IMG_20150626_214946.jpg: open failed: ENOENT (No such file or directory)tego FileOutputStream outStream = new FileOutputStream(dst);kroku. Zgodnie z tekstem zdaję sobie sprawę, że plik nie istnieje, więc sprawdzam go i w dst.mkdir();razie potrzeby dzwonię , ale nadal nie pomaga. Próbowałem też sprawdzić dst.canWrite();i wrócił false. Czy to może być przyczyną problemu? I tak mam <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>.
Mike B.
1
@ ViktorBrešan Po API 19 można korzystać z automatycznego zarządzania zasobami Java, definiując strumienie wejściowe i wyjściowe na początku próbytry ( FileInputStream inStream = new FileInputStream(src); FileOutputStream outStream = new FileOutputStream(dst) ) {
AlbertMarkovski
Czy jest jakiś sposób, aby to rozwiązanie opublikowało swoje postępy onProgressUpdate, aby mógłbym pokazać go w pasku postępu? W przyjętym rozwiązaniu mogę obliczyć postęp w pętli while, ale nie widzę tutaj, jak to zrobić.
George Bezerra
31

Rozszerzenie Kotlin dla niego

fun File.copyTo(file: File) {
    inputStream().use { input ->
        file.outputStream().use { output ->
            input.copyTo(output)
        }
    }
}
Dima Rostopira
źródło
To najbardziej zwięzła, ale elastyczna odpowiedź. Prostsze odpowiedzi nie uwzględniają identyfikatorów URI otwieranych za pośrednictwem contentResolver.openInputStream(uri).
AjahnCharles
6
Kotlin to miłość, Kotlin to życie!
Dev Aggarwal
17

Te działały dla mnie dobrze

public static void copyFileOrDirectory(String srcDir, String dstDir) {

    try {
        File src = new File(srcDir);
        File dst = new File(dstDir, src.getName());

        if (src.isDirectory()) {

            String files[] = src.list();
            int filesLength = files.length;
            for (int i = 0; i < filesLength; i++) {
                String src1 = (new File(src, files[i]).getPath());
                String dst1 = dst.getPath();
                copyFileOrDirectory(src1, dst1);

            }
        } else {
            copyFile(src, dst);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static void copyFile(File sourceFile, File destFile) throws IOException {
    if (!destFile.getParentFile().exists())
        destFile.getParentFile().mkdirs();

    if (!destFile.exists()) {
        destFile.createNewFile();
    }

    FileChannel source = null;
    FileChannel destination = null;

    try {
        source = new FileInputStream(sourceFile).getChannel();
        destination = new FileOutputStream(destFile).getChannel();
        destination.transferFrom(source, 0, source.size());
    } finally {
        if (source != null) {
            source.close();
        }
        if (destination != null) {
            destination.close();
        }
    }
}
Bojan Kseneman
źródło
13

Jest to proste w Androidzie O (API 26), jak widać:

  @RequiresApi(api = Build.VERSION_CODES.O)
  public static void copy(File origin, File dest) throws IOException {
    Files.copy(origin.toPath(), dest.toPath());
  }
Chytre spojrzenie
źródło
10

Na odpowiedź może być za późno, ale najwygodniejszym sposobem jest użycie

FileUtils„s

static void copyFile(File srcFile, File destFile)

np. to zrobiłem

`

private String copy(String original, int copyNumber){
    String copy_path = path + "_copy" + copyNumber;
        try {
            FileUtils.copyFile(new File(path), new File(copy_path));
            return copy_path;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

`

stopBugs
źródło
20
FileUtils nie istnieje natywnie w systemie Android.
Berga
2
Ale jest biblioteka wykonana przez Apache, która robi to i więcej: commons.apache.org/proper/commons-io/javadocs/api-2.5/org/…
Alessandro Muzzi
7

O wiele prostsze teraz dzięki Kotlin:

 File("originalFileDir", "originalFile.name")
            .copyTo(File("newFileDir", "newFile.name"), true)

truelub falsesłuży do zastąpienia pliku docelowego

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.io.-file/copy-to.html

Blundell
źródło
Nie takie proste, jeśli Twój plik pochodzi z Uri przeznaczonego dla galerii.
AjahnCharles
Przeczytaj poniższe komentarze tej odpowiedzi: „Ta odpowiedź jest aktywnie szkodliwa i nie zasługuje na głosy, które otrzyma. Nie powiedzie się, jeśli Uri jest zawartością: // lub innym nie-plikowym Uri”. (Przegłosowałem - chciałem tylko wyjaśnić, że to nie srebrna kula)
AjahnCharles
5

Oto rozwiązanie, które faktycznie zamyka strumienie wejściowe / wyjściowe, jeśli podczas kopiowania wystąpi błąd. To rozwiązanie wykorzystuje metody apache Commons IO IOUtils do kopiowania i obsługi zamykania strumieni.

    public void copyFile(File src, File dst)  {
        InputStream in = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(src);
            out = new FileOutputStream(dst);
            IOUtils.copy(in, out);
        } catch (IOException ioe) {
            Log.e(LOGTAG, "IOException occurred.", ioe);
        } finally {
            IOUtils.closeQuietly(out);
            IOUtils.closeQuietly(in);
        }
    }
SBerg413
źródło
Wygląda to prosto
Serg Burlaka
2

w kotlin, po prostu:

val fileSrc : File = File("srcPath")
val fileDest : File = File("destPath")

fileSrc.copyTo(fileDest)
Sodino
źródło