我是Java程序员的初学者
今天,我练习了如何在java中复制文件,并尝试按照本教程
http://www.journaldev.com/861/4-ways-to-copy-file-in-java
完成本教程后,我运行了JMH Benchmark以检查性能,并使用57MB的txt文件
nioFiles和NIOChannel之间存在性能差距,大于我的预期。
Benchmark Mode Cnt Score Error Units
CompressTest.fileCopyUsingNIOChannelClass thrpt 10 22.465 ± 2.996 ops/s
CompressTest.fileCopyWithNIOFiles thrpt 10 0.843 ± 0.488 ops/s
这是我用过的代码
@Warmup(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
@Fork(1)
@State(Scope.Benchmark)
public class CompressTest
{
final static Path source = Paths.get("c:/temp/system.out.lambda.txt");
final static Path target = Paths.get("c:/temp/copied.lambda.txt");
public static void main(String[] args) throws RunnerException, IOException {
Main.main(args);
}
@Benchmark
public static void fileCopyWithNIOFiles() throws IOException{
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
}
@Benchmark
public static void fileCopyUsingNIOChannelClass() throws IOException
{
File fileToCopy = new File("c:/temp/system.out.lambda.txt");
FileInputStream inputStream = new FileInputStream(fileToCopy);
FileChannel inChannel = inputStream.getChannel();
File newFile = new File("c:/temp/testcopied.txt");
FileOutputStream outputStream = new FileOutputStream(newFile);
FileChannel outChannel = outputStream.getChannel();
inChannel.transferTo(0, fileToCopy.length(), outChannel);
inputStream.close();
outputStream.close();
}
}
所以我想问一下,我做错了吗?或者你能解释为什么会这样吗?
有人问,所以我试过了另一个文件。结果是348MB avi文件及以下内容。
Benchmark Mode Cnt Score Error Units
CompressTest.fileCopyUsingNIOChannelClass thrpt 10 3.142 ± 0.738 ops/s
CompressTest.fileCopyWithNIOFiles thrpt 10 1.991 ± 0.350 ops/s
使用nioFile的静态文件副本比使用NIOChannel慢。
我刷新了所有内容,只是再次测试了,这就是重新开始。使用57MB的txt文件并将预热迭代设置为10。
Benchmark Mode Cnt Score Error Units
CompressTest.fileCopyUsingNIOChannelClass thrpt 10 23.442 ± 3.224 ops/s
CompressTest.fileCopyWithNIOFiles thrpt 10 12.328 ± 2.128 ops/s
这个结果比第一个结果更容易接受,但是nioFile复制的速度仍然是NIOChannel的近一半。
P.S。 :如果有更好的方法来复制文件,请告诉我。我真的想了解更多有关java的信息,谢谢。
答案 0 :(得分:11)
TL; DR - 这是缓存问题
在任务管理器中运行基准测试打开 Performance 选项卡时,您将看到差异的来源。
在Files.copy
测试期间,您可能会看到高磁盘写入速度。但是当transferTo
测试运行时,磁盘将几乎空闲!这意味着实际上没有数据写入设备 - 复制在内存中执行。这显然要快得多。
使用CopyFileEx
WinAPI函数实现Java Files.copy
方法。没有明确规范CopyFileEx
如何在内部工作,但观察到它会做一些实际的磁盘I / O.
反过来,transferTo
会进行一系列ReadFile
/ WriteFile
次来电。 WriteFile
函数不保证数据立即写入磁盘。它可能会将数据放入OS磁盘缓存中,并在后面的某个时间执行实际的设备I / O.
答案 1 :(得分:1)