在Java中复制文件的标准简洁方法?

时间:2020-03-06 14:28:28  来源:igfitidea点击:

一直困扰着我,用Java复制文件的唯一方法是打开流,声明缓冲区,读入一个文件,循环遍历并将其写出到另一流。 Web上散布着这种解决方案的相似但仍然略有不同的实现。

有没有更好的方法可以保留在Java语言的范围内(意味着不涉及执行OS特定的命令)?也许在某个可靠的开源实用程序包中,这至少会掩盖这种底层实现并提供一线解决方案?

解决方案

如上面的工具包所述,Apache Commons IO是必经之路,特别是FileUtils.copyFile();。它为我们处理所有繁重的工作。

另外,请注意,FileUtils的最新版本(例如2.0.1发行版)增加了使用NIO复制文件的功能。 NIO可以大大提高文件复制性能,这在很大程度上是因为NIO例程将复制直接推迟到OS /文件系统,而不是通过在Java层中读写字节来处理。因此,如果我们要寻找性能,可能值得检查一下我们是否使用了最新版本的FileUtils。

我会避免使用像Apache Commons这样的大型api。这是一个简单的操作,它内置在新NIO包中的JDK中。以前的答案中已经链接了这种方法,但是NIO api中的关键方法是新功能" transferTo"和" transferFrom"。

http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html#transferTo(long,%20long,%20java.nio.channels.WritableByteChannel)

链接的文章之一显示了一种很好的方法,可以使用transferFrom将功能集成到代码中:

public static void copyFile(File sourceFile, File destFile) throws IOException {
    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();
        }
    }
}

学习NIO可能会有些棘手,因此我们可能只想在开始尝试通宵学习NIO之前就信任此机制。从个人经验来看,如果我们没有经验,并且是通过java.io流介绍给IO的,那将是一件非常困难的事情。

请注意,所有这些机制都仅复制文件的内容,而不复制诸如权限之类的元数据。因此,如果我们要在Linux上复制或者移动可执行文件.sh文件,则新文件将不可执行。

为了真正复制或者移动文件,即获得与从命令行复制相同的结果,我们实际上需要使用本机工具。 Shell脚本或者JNI。

显然,这可以在Java 7 http://today.java.net/pub/a/today/2008/07/03/jsr-203-new-file-apis.html中修复。手指交叉了!

在Java 7中作为标准功能提供,path.copyTo:
http://openjdk.java.net/projects/nio/javadoc/java/nio/file/Path.html
http://java.sun.com/docs/books/tutorial/essential/io/copy.html

我不敢相信他们花了这么长时间来标准化文件复制这样的常见和简单的方法:(

Google的Guava库也有一个复制方法:

<DD>

public static void <B>copy(<A HREF="http://download.oracle.com/javase/6/docs/api/java/io/File.html?is-external=true" rel="nofollow noreferrer" title="class or interface in java.io">File from,
                        <A HREF="http://download.oracle.com/javase/6/docs/api/java/io/File.html?is-external=true" rel="nofollow noreferrer" title="class or interface in java.io">File to)
                 throws <A HREF="http://download.oracle.com/javase/6/docs/api/java/io/IOException.html?is-external=true" rel="nofollow noreferrer" title="class or interface in java.io">IOException

<DL>
<DD>将所有字节从一个文件复制到另一个文件。

<B>投掷:
IOException如果发生I / O错误
如果from.equals(to)则返回IllegalArgumentException。