一直困扰我的是,在Java中复制文件的唯一方法包括打开流,声明缓冲区,读入一个文件,循环遍历它,并将其写入到另一个steam。网络上充斥着类似的,但仍然略有不同的这类解决方案的实现。

是否有一种更好的方法能够保持在Java语言的范围内(即不涉及执行特定于操作系统的命令)?也许在一些可靠的开源实用程序包中,它至少会模糊这个底层实现,并提供一行解决方案?


当前回答

现在在Java 7中,你可以使用下面的try-with-resource语法:

public static void copyFile( File from, File to ) throws IOException {

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

    try (
        FileChannel in = new FileInputStream( from ).getChannel();
        FileChannel out = new FileOutputStream( to ).getChannel() ) {

        out.transferFrom( in, 0, in.size() );
    }
}

或者,更好的是,这也可以使用Java 7中引入的新Files类来完成:

public static void copyFile( File from, File to ) throws IOException {
    Files.copy( from.toPath(), to.toPath() );
}

很时髦,是吧?

其他回答

我会避免使用像apache commons这样的mega api。这是一个简单的操作,它内置于新的NIO包中的JDK中。在之前的回答中已经链接到它,但是NIO api中的关键方法是新函数“transferTo”和“transferFrom”。

http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html transferTo(长,长% 20,% 20 java.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流。

正如上面提到的工具包,Apache Commons IO是可行的方法,特别是FileUtils.copyFile();它能帮你处理所有的重担。

作为附注,请注意FileUtils的最新版本(例如2.0.1版本)已经添加了用于复制文件的NIO;NIO可以显著提高文件复制性能,这在很大程度上是因为NIO例程直接将复制推迟到OS/文件系统,而不是通过Java层读写字节来处理它。因此,如果您正在寻找性能,可能值得检查您使用的是最新版本的FileUtils。

快速和工作与所有版本的Java和Android:

private void copy(final File f1, final File f2) throws IOException {
    f2.createNewFile();

    final RandomAccessFile file1 = new RandomAccessFile(f1, "r");
    final RandomAccessFile file2 = new RandomAccessFile(f2, "rw");

    file2.getChannel().write(file1.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, f1.length()));

    file1.close();
    file2.close();
}

请注意,所有这些机制都只复制文件的内容,而不是权限等元数据。因此,如果您要复制或移动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

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