Como fazer uma cópia de um arquivo no android?

Respostas:

327

Para copiar um arquivo e salvá-lo no caminho de destino, você pode usar o método abaixo.

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

Na API 19+, você pode usar o 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);
            }
        }
    }
}
Rakshi
fonte
8
Obrigado. depois de bater a cabeça, descobri que faltava permissão para gravar no armazenamento externo. agora funciona bem.
AS
8
@ mohitum007 se o arquivo não conseguir copiar, uma exceção será lançada. use um bloco try catch ao chamar o método
Nima G
9
Se uma exceção for lançada, os fluxos não serão fechados até serem coletados como lixo, e isso não é bom . Considere fechá-los finally.
Pang
1
@Pang. Você está certo. O que é pior: in / out.close () deve ser chamado ou, caso contrário, haverá um vazamento de recursos no sistema operacional subjacente, pois o GC nunca fechará os descritores de arquivos abertos. O GC não pode fechar recursos do SO externos à JVM, como descritores de arquivo ou soquetes. Aqueles deve estar sempre fechado em uma cláusula finalmente programaticamente ou uso try-with-novo recurso sintaxe: docs.oracle.com/javase/tutorial/essential/exceptions/...
earizon
4
Por favor, feche os dois Streams dentro de um finalmente; se houver uma exceção, a memória do seu stream não será coletada.
22416 Pozuelog
121

Como alternativa, você pode usar o FileChannel para copiar um arquivo. Ele pode ser mais rápido do que o método de cópia byte ao copiar um arquivo grande. Você não pode usá-lo se o seu arquivo tiver mais de 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
fonte
3
transferTo pode lançar uma exceção e, nesse caso, você está deixando os fluxos abertos. Assim como Pang e Nima comentaram em resposta aceita.
Viktor Bresan
Além disso, transferTo deve ser chamado dentro do loop, pois não garante que irá transferir o valor total solicitado.
Viktor Brešan 29/11
Eu tentei sua solução e ela falhou com a exceção java.io.FileNotFoundException: /sdcard/AppProj/IMG_20150626_214946.jpg: open failed: ENOENT (No such file or directory)na FileOutputStream outStream = new FileOutputStream(dst);etapa. De acordo com o texto, percebo que o arquivo não existe, então verifico e ligo dst.mkdir();se necessário, mas ainda não ajuda. Eu também tentei verificar dst.canWrite();e ele retornou false. Esta é a fonte do problema? E sim, eu tenho <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>.
Mike B.
1
@ ViktorBrešan Depois de API 19 você pode usar a gestão de recursos automática Java, definindo a entrada e saída fluxos na abertura de sua tentativatry ( FileInputStream inStream = new FileInputStream(src); FileOutputStream outStream = new FileOutputStream(dst) ) {
AlbertMarkovski
Existe alguma maneira de fazer com que esta solução publique seu progresso para onProgressUpdateque eu possa mostrá-la em uma ProgressBar? Na solução aceita, posso calcular o progresso no loop while, mas não consigo ver como fazê-lo aqui.
George Bezerra
31

Extensão Kotlin para ele

fun File.copyTo(file: File) {
    inputStream().use { input ->
        file.outputStream().use { output ->
            input.copyTo(output)
        }
    }
}
Dima Rostopira
fonte
Essa é a resposta mais concisa e flexível. As respostas mais simples não conseguem explicar os URIs abertos via contentResolver.openInputStream(uri).
AjahnCharles
6
Kotlin é amor, Kotlin é vida!
Dev Aggarwal
17

Eles funcionaram bem para mim

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
fonte
13

Isso é simples no Android O (API 26), como você vê:

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

Pode ser tarde demais para uma resposta, mas a maneira mais conveniente é usar

FileUtilsé

static void copyFile(File srcFile, File destFile)

por exemplo, foi o que eu fiz

`

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
fonte
20
O FileUtils não existe nativamente no Android.
The Berga
2
Mas há uma biblioteca criada pelo Apache que faz isso e muito mais: commons.apache.org/proper/commons-io/javadocs/api-2.5/org/…
Alessandro Muzzi
7

Muito mais simples agora com Kotlin:

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

trueou falseé para substituir o arquivo de destino

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

Blundell
fonte
Não é tão simples se o seu arquivo vier de uma intenção da Galeria Uri.
AjahnCharles
Leia os comentários abaixo dessa resposta: "Esta resposta é ativamente prejudicial e não merece os votos que obtém. Falha se o Uri for um conteúdo: // ou qualquer outro Uri que não seja de arquivo." (Eu fiz upvote - Eu só queria esclarecer que não é uma bala de prata)
AjahnCharles
5

Aqui está uma solução que realmente fecha os fluxos de entrada / saída se ocorrer um erro durante a cópia. Esta solução utiliza os métodos apache Commons IO IOUtils para copiar e manipular o fechamento de fluxos.

    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
fonte
Parece simples
Serg Burlaka 06/04
2

no kotlin, apenas:

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

fileSrc.copyTo(fileDest)
Sodino
fonte