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

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


当前回答

public static void copyFile(File src, File dst) throws IOException
{
    long p = 0, dp, size;
    FileChannel in = null, out = null;

    try
    {
        if (!dst.exists()) dst.createNewFile();

        in = new FileInputStream(src).getChannel();
        out = new FileOutputStream(dst).getChannel();
        size = in.size();

        while ((dp = out.transferFrom(in, p, size)) > 0)
        {
            p += dp;
        }
    }
    finally {
        try
        {
            if (out != null) out.close();
        }
        finally {
            if (in != null) in.close();
        }
    }
}

其他回答

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

很时髦,是吧?

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

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

上述代码有三个可能的问题:

如果getChannel抛出异常,则可能泄漏一个开放流。 对于大文件,您可能会尝试一次传输超出操作系统处理能力的文件。 您忽略了transferFrom的返回值,因此它可能只是复制文件的一部分。

这就是为什么org.apache.tools.ant.util.ResourceUtils.copyResource如此复杂。还要注意,虽然transferFrom没问题,但transferTo会在Linux上的JDK 1.4上中断(参见Bug ID:5056395)

这里有三种方法,您可以轻松地复制文件与一行代码!

Java7:

java.nio.file.Files #副本

private static void copyFileUsingJava7Files(File source, File dest) throws IOException {
    Files.copy(source.toPath(), dest.toPath());
}

公共汽车共享10:

文件实用程序#复制文件

private static void copyFileUsingApacheCommonsIO(File source, File dest) throws IOException {
    FileUtils.copyFile(source, dest);
}

番石榴:

文件#复制

private static void copyFileUsingGuava(File source,File dest) throws IOException{
    Files.copy(source,dest);          
}

我会避免使用像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流。