语境

我正在尝试在数据传输期间获得反馈。发生不同的情况,但是我要处理的特定情况是FileInputStream到FileOutputStream的副本。

实际的流复制循环是通过org.apache.commons.io.IOUtils完成的。

请注意,我是一位经验丰富的开发人员,但是我是Java新手。 JVM的优化对我而言并不为人所知。

问题

我将FileOutputStream包装在java.io.FilterOutputStream中以拦截传输并计数,如下所示:

FileInputStream input = new FileInputStream(new File("path"));
FileOutputStream output = new FileOutputStream(new File("path2"));
FilterOutputStream filterOutput = new FilterOutputStream(output);
IOUtils.copyLarge(input, filterOutput, new byte[32 * 1024]);


现在,当我执行此操作时,删除了实际的“执行某项操作”(在上面的示例中,删除了我的基本FilterOutputStream实现,以免影响测试),并在5-10秒内复制了一个450Mb的文件(没有FilterOutputStream)包装)约8分钟。

几个事实


在Windows x64 8核心机器上测得
从本地局域网复制到本机的SSD
一个核心处于100%繁忙状态,直到操作结束
网络和磁盘几乎不忙(1-2%)
我已经在文件流周围使用具有可变缓冲区大小的缓冲输入/输出流进行了测试,而不使用它们。
我改变了实际的数据缓冲区大小。
以上两种变化均未证明对有和无之间的数量级差异有任何有意义的影响
FilterOutputStream包装。




为什么会发生这种情况?有什么办法可以解决它?

我猜想JVM能够检测文件复制的标准模式并将其直接委派给OS。对我来说,将其包装在Buffered流中似乎有点奇怪,但由于FilterOutputStream间接调用了write方法,因此无法做到这一点。

目前,我所看到的唯一解决方法是直接在复制循环中实现侦听器,而不是通过管道传递OutputStreams,但是由于这需要重新实现循环而不是使用Apache utils,并在多层API中添加和传递该侦听器,在走这条路之前,我正在寻找信息。

最佳答案

FilterOutputStream将为以下方法逐字节复制:


  公共无效write(byte [] b,
           诠释
           int len)
             引发IOException
  
  将指定字节数组中从offset off开始的len个字节写入此输出流。
  FilterOutputStream的write方法在每个字节上调用一个参数的write方法以输出。
  
  请注意,此方法不会使用相同的参数调用其基础输入流的write方法。 FilterOutputStream的子类应提供此方法的更有效实现。

关于java - 为什么截取FileInputStream到FileOutputStream的传输速度与FilterOutputStream数量级比较慢?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37446021/

10-08 20:44