有人可以解释transferTo
方法如何以看似1000+ MB /秒的速度复制文件。我使用372MB二进制文件运行了一些测试并且第一个副本很慢,但如果我更改输出名称并再次运行它,输出目录中会出现一个额外的文件,只需180ms,超过2000 MB /秒。这里发生了什么?我正在运行Windows 7。
private static void doCopyNIO(String inFile, String outFile) {
FileInputStream fis = null;
FileOutputStream fos = null;
FileChannel cis = null;
FileChannel cos = null;
long len = 0, pos = 0;
try {
fis = new FileInputStream(inFile);
cis = fis.getChannel();
fos = new FileOutputStream(outFile);
cos = fos.getChannel();
len = cis.size();
while (pos < len) {
pos += cis.transferTo(pos, (1024 * 1024 * 10), cos); // 10M
}
fos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cos != null) { try { cos.close(); } catch (Exception e) { } }
if (fos != null) { try { fos.close(); } catch (Exception e) { } }
if (cis != null) { try { cis.close(); } catch (Exception e) { } }
if (fis != null) { try { fis.close(); } catch (Exception e) { } }
}
}
答案 0 :(得分:6)
关键是“第一次”。您的操作系统已将整个文件缓存在RAM中(目前372MB并不多),因此唯一的开销是将零复制缓冲区翻转到内存映射空间所需的时间。如果您刷新缓存(不知道如何在Windows上执行此操作;如果文件位于外部驱动器上,您可以拔下并重新插入),您将看到安定下来读取速率,如果您强制操作系统刷新写入,如果你有硬盘,你的程序将会阻塞大约10秒钟。
答案 1 :(得分:2)
我猜测一旦文件被读取一次,操作系统就会对其进行缓存,以加快后续读取速度。此外,NTFS中的一个名为Single Instance Storage的功能也可能发挥作用,如Wikipedia所述:
当有多个目录具有不同但相似的文件时,其中一些文件可能具有相同的内容。单实例存储允许将相同的文件合并到一个文件中,并创建对该合并文件的引用。
https://en.wikipedia.org/wiki/NTFS#Single_Instance_Storage_.28SIS.29
我不确定这是否是你所看到的,但我唯一能想到的是有道理的。
答案 2 :(得分:1)
这似乎在缓冲IO性能方面是正确的....发生的事情是你正在阅读并将文件仅写入内存,然后在后台,操作系统将输出文件'刷新'到磁盘。您没有测量将文件写入磁盘所需的时间,而只是测量内存。
您可能需要再次尝试(出于教育目的)使用设置的DSYNC选项,当您使用带有Files.newOutputStream(...)的new-to-Java7 DSYNC OpenOption打开FileOutputStream时。
这样,文件将在写入输出流的同时写入磁盘。输出文件不会有任何内存缓存。