如何在Android中制作文件的副本?


Answers:


326

要复制文件并将其保存到目标路径,可以使用以下方法。

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

在API 19+上,您可以使用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);
            }
        }
    }
}

8
谢谢。敲打我的头后,我发现问题是缺少写外部存储的权限。现在工作正常。
AS

8
@ mohitum007如果文件复制失败,则会引发异常。调用方法时使用try catch块。
尼玛G

9
如果抛出异常,则只有在对流进行垃圾回收之前,这些流才会被关闭,这不是很好。考虑关闭它们finally

1
@庞 你是对的。更糟糕的是,必须调用in / out.close(),否则底层操作系统中会发生资源泄漏,因为GC永远不会关闭打开的文件描述符。GC无法关闭JVM外部的OS资源,例如文件描述符或套接字。:那些必须在finally从句关闭通过程序或使用try与资源新语法docs.oracle.com/javase/tutorial/essential/exceptions/...
earizon

4
请关闭两个流,最后,如果有Excepcion,则不会收集流的内存。
pozuelog '16

121

或者,您可以使用FileChannel复制文件。复制大文件时,它可能比字节复制方法要快。但是,如果文件大于2GB,则不能使用它。

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可能会引发异常,在这种情况下,您将流保持打开状态。就像庞(Pang)和尼玛(Nima)在接受的答案中评论一样。
维克多·布雷桑(ViktorBrešan)2014年

另外,应该在循环内调用transferTo,因为它不能保证将转移所请求的总额。
维克多·布雷桑(ViktorBrešan)2014年

我尝试了您的解决方案,但java.io.FileNotFoundException: /sdcard/AppProj/IMG_20150626_214946.jpg: open failed: ENOENT (No such file or directory)FileOutputStream outStream = new FileOutputStream(dst);步骤对我来说失败了。根据文字,我意识到该文件不存在,因此我检查了文件并dst.mkdir();在需要时调用,但仍然无济于事。我也尝试检查dst.canWrite();并退回false。这可能是问题的根源吗?是的,我有<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Mike B.

1
@ViktorBrešan在API 19之后,您可以通过在尝试开始时定义输入和输出流来使用Java自动资源管理try ( FileInputStream inStream = new FileInputStream(src); FileOutputStream outStream = new FileOutputStream(dst) ) {
AlbertMarkovski

有什么方法可以使此解决方案将其进度发布到onProgressUpdate,以便可以在ProgressBar中显示它?在公认的解决方案中,我可以在while循环中计算进度,但是在这里看不到如何做。
乔治·贝塞拉

30

Kotlin扩展

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

这是最简洁但最灵活的答案。比较简单的答案无法说明通过开启的URI contentResolver.openInputStream(uri)
AjahnCharles

6
Kotlin是爱,Kotlin是生活!
Dev Aggarwal

17

这些对我来说很好

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

如您所见,这在Android O(API 26)上很简单:

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

10

答案可能为时已晚,但最方便的方法是使用

FileUtils

static void copyFile(File srcFile, File destFile)

例如,这就是我所做的

`

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在Android中本身不存在。
的贝尔加

2
但是有一个由Apache制作的库,可以完成更多工作: commons.apache.org/proper/commons-io/javadocs/api-2.5/org/…–
Alessandro Muzzi

7

Kotlin现在简单得多:

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

truefalse用于覆盖目标文件

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


如果您的文件来自库意图Uri,则不是那么简单。
AjahnCharles

阅读该答案下方的评论:“此答案是有害的,不应该得到它的投票。如果Uri是content://或任何其他非文件Uri,则它将失败。” (我确实投票赞成-我只是想澄清一下这不是银弹)
AjahnCharles

5

如果复制时发生错误,这是一种实际上关闭输入/输出流的解决方案。该解决方案利用apache Commons IO IOUtils方法复制和处理流的关闭。

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

看起来很简单
Serg Burlaka

2

在Kotlin中,只是:

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

fileSrc.copyTo(fileDest)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.