FileChannel.transferTo用于Windows中的大文件

时间:2011-09-11 16:05:00

标签: java nio file-copying

使用Java NIO使用可以更快地复制文件。我发现两种方法主要是通过互联网来完成这项工作。

public static void copyFile(File sourceFile, File destinationFile) throws IOException {
    if (!destinationFile.exists()) {
        destinationFile.createNewFile();
    }

    FileChannel source = null;
    FileChannel destination = null;
    try {
        source = new FileInputStream(sourceFile).getChannel();
        destination = new FileOutputStream(destinationFile).getChannel();
        destination.transferFrom(source, 0, source.size());
    } finally {
        if (source != null) {
            source.close();
        }
        if (destination != null) {
            destination.close();
        }
    }
}

20 very useful Java code snippets for Java Developers中,我发现了不同的评论和伎俩:

public static void fileCopy(File in, File out) throws IOException {
    FileChannel inChannel = new FileInputStream(in).getChannel();
    FileChannel outChannel = new FileOutputStream(out).getChannel();
    try {
        // inChannel.transferTo(0, inChannel.size(), outChannel); // original -- apparently has trouble copying large files on Windows
        // magic number for Windows, (64Mb - 32Kb)
        int maxCount = (64 * 1024 * 1024) - (32 * 1024);
        long size = inChannel.size();
        long position = 0;
        while (position < size) {
            position += inChannel.transferTo(position, maxCount, outChannel);
        }
    } finally {
        if (inChannel != null) {
            inChannel.close();
        }
        if (outChannel != null) {
            outChannel.close();
        }
    }
}

但我没有找到或理解

的含义
  

“Windows的幻数,(64Mb - 32Kb)”

它表示inChannel.transferTo(0, inChannel.size(), outChannel)在windows中有问题,32768(=(64 * 1024 * 1024) - (32 * 1024))字节对于此方法是最佳的。

3 个答案:

答案 0 :(得分:7)

Windows对最大传输大小有硬性限制,如果超过它,则会出现运行时异常。所以你需要调整。你给出的第二个版本是优越的,因为它不假设文件是​​通过一次transferTo()调用完全传输的,这与Javadoc一致。

无论如何,将传输大小设置为大约1MB都是毫无意义的。

编辑您的第二个版本存在缺陷。您应该按每次转移的金额递减size。它应该更像是:

while (position < size) {
    long count = inChannel.transferTo(position, size, outChannel);
    if (count > 0)
    {
        position += count;
        size-= count;
    }
}

答案 1 :(得分:0)

我读过它是为了与Windows 2000操作系统兼容。

来源:http://www.rgagnon.com/javadetails/java-0064.html

引用:在win2000中,transferTo()不传输文件&gt;超过2 ^ 31-1个字节。它抛出了一个异常“java.io.IOException:存在不足的系统资源来完成所请求的服务。”解决方法是每次循环复制64Mb,直到没有更多数据。

答案 2 :(得分:-1)

似乎有传闻证据表明,在某些Windows版本上尝试一次传输超过64MB会导致副本速度变慢。因此检查:这似乎是在Windows上实现transferTo操作的底层本机代码的一些细节的结果。