Come fare una copia di un file in Android?


Risposte:


327

Per copiare un file e salvarlo sul percorso di destinazione è possibile utilizzare il metodo seguente.

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();
    }
}

Su API 19+ puoi utilizzare Java Automatic Resource Management:

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);
            }
        }
    }
}

8
Grazie. dopo aver sbattuto la testa ho scoperto che il problema mancava dell'autorizzazione per scrivere su un archivio esterno. ora funziona benissimo.
AS

8
@ mohitum007 se il file non viene copiato, viene generata un'eccezione. utilizzare un blocco catch catch quando si chiama il metodo
Nima G,

9
Se viene generata un'eccezione, i flussi non verrebbero chiusi fino a quando non saranno raccolti nella spazzatura, e non va bene . Valuta di chiuderli finally.
Pang

1
@Pang. Hai ragione. Quel che è peggio, deve essere chiamato in / out.close () o altrimenti ci sarà una perdita di risorse nel sistema operativo sottostante, poiché il GC non chiuderà mai i descrittori di file aperti. GC non può chiudere le risorse del sistema operativo esterne alla JVM come descrittori di file o socket. Questi devono sempre essere chiusi in una clausola di fine programmaticamente o utilizzare la nuova sintassi di prova con risorsa: docs.oracle.com/javase/tutorial/essential/exceptions/…
earizon

4
Per favore, chiudi entrambi gli stream all'interno di a, infine, se c'è un'eccezione, la memoria dei tuoi stream non verrà raccolta.
pozuelog,

121

In alternativa, è possibile utilizzare FileChannel per copiare un file. Si potrebbe essere più veloce rispetto al metodo di copia di byte quando si copia un file di grandi dimensioni. Non puoi usarlo se il tuo file è più grande di 2 GB però.

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();
}

3
transferTo può generare un'eccezione e in tal caso si lasciano flussi aperti. Proprio come Pang e Nima hanno commentato nella risposta accettata.
Viktor Brešan,

Inoltre, transferTo dovrebbe essere chiamato all'interno del loop poiché non garantisce che trasferirà l'importo totale richiesto.
Viktor Brešan,

Ho provato la tua soluzione e per me non ha funzionato, ad eccezione java.io.FileNotFoundException: /sdcard/AppProj/IMG_20150626_214946.jpg: open failed: ENOENT (No such file or directory)del FileOutputStream outStream = new FileOutputStream(dst);passaggio. Secondo il testo, mi rendo conto che il file non esiste, quindi lo controllo e lo chiamo dst.mkdir();se necessario, ma non aiuta ancora. Ho anche provato a controllare dst.canWrite();ed è tornato false. Può questa essere la fonte del problema? E sì, l'ho fatto <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>.
Mike B.

1
@ ViktorBrešan Dopo l'API 19 puoi utilizzare la gestione automatica delle risorse Java definendo i flussi in e out nell'apertura del tuo tentativotry ( FileInputStream inStream = new FileInputStream(src); FileOutputStream outStream = new FileOutputStream(dst) ) {
AlbertMarkovski,

Esiste un modo per pubblicare questa soluzione sui suoi progressi onProgressUpdate, in modo che io possa mostrarlo in ProgressBar? Nella soluzione accettata posso calcolare i progressi nel ciclo while, ma non riesco a vedere come farlo qui.
George Bezerra,

31

Estensione Kotlin per questo

fun File.copyTo(file: File) {
    inputStream().use { input ->
        file.outputStream().use { output ->
            input.copyTo(output)
        }
    }
}

Questa è la risposta più concisa ma flessibile. Le risposte più semplici non riescono a tenere conto degli URI aperti tramite contentResolver.openInputStream(uri).
AjahnCharles il

6
Kotlin è amore, Kotlin è vita!
Dev Aggarwal,

17

Questi hanno funzionato bene per me

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();
        }
    }
}

13

Questo è semplice su Android O (API 26), come vedi:

  @RequiresApi(api = Build.VERSION_CODES.O)
  public static void copy(File origin, File dest) throws IOException {
    Files.copy(origin.toPath(), dest.toPath());
  }

10

Potrebbe essere troppo tardi per una risposta, ma il modo più conveniente è usare

FileUtils'S

static void copyFile(File srcFile, File destFile)

ad esempio questo è quello che ho fatto

`

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;
    }

`


20
FileUtils non esiste nativamente in Android.
Berga,

2
Ma c'è una libreria creata da Apache che fa questo e altro: commons.apache.org/proper/commons-io/javadocs/api-2.5/org/…
Alessandro Muzzi,

7

Molto più semplice ora con Kotlin:

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

trueo falseserve per sovrascrivere il file di destinazione

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


Non è così semplice se il tuo file proviene da un Uri intento Galleria.
AjahnCharles il

Leggi i commenti sottostanti che rispondono: "Questa risposta è attivamente dannosa e non merita i voti che ottiene. Non riesce se l'Uri è un contenuto: // o qualsiasi altro Uri non file." (Ho votato a favore - volevo solo chiarire che non è un proiettile d'argento)
AjahnCharles il

5

Ecco una soluzione che chiude effettivamente i flussi di input / output se si verifica un errore durante la copia. Questa soluzione utilizza i metodi IO IOUtils di Apache Commons sia per la copia che per la gestione della chiusura di flussi.

    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);
        }
    }

Sembra semplice
Serg Burlaka,

2

in kotlin, solo:

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

fileSrc.copyTo(fileDest)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.