为什么拦截FileInputStream到FileOutputStream传输FilterOutputStream的数量级要慢一些?

时间:2016-05-25 19:29:14

标签: java jvm fileinputstream fileoutputstream

上下文

我试图在数据传输过程中获得反馈。出现了不同的情况,但我正在处理的特定情况是FileInputStream到FileOutputStream副本。

使用org.apache.commons.io.IOUtils完成实际的流复制循环。

请注意,我是一名经验丰富的开发人员,但我是一名java新手。我不了解JVM的优化。

问题

我在java.io.FilterOutputStream中包装FileOutputStream来拦截传输并按如下方式计算:

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删除了我的实现,以免影响测试),复制450Mb文件从5-10secs(没有FilterOutputStream包装)下降到大约8分钟。

一些事实

  • 在Windows x64 8核心机上测量
  • 从本地局域网复制到我的机器的SSD
  • 一个核心100%忙碌直到操作结束
  • 网络和磁盘几乎没有(1-2%)
  • 我使用不同缓冲区大小的文件流使用缓冲输入/输出流进行测试,而不使用它们。
  • 我改变了实际的数据缓冲区大小。
  • 以上两种变体中没有一种被证明对有和没有的数量级差异有任何有意义的影响 FilterOutputStream包装。

问题

为什么会这样?有没有办法解决它?

我猜JVM能够检测文件复制的标准模式并将其直接委托给操作系统。对我来说似乎有点奇怪,它会在Buffered流中包含它,但是不能通过FilterOutputStream指向的write方法来完成它。

现在,我看到的唯一工作就是在复制循环中实现一个侦听器,而不是管道OutputStreams,但是因为这需要重新实现循环而不是使用Apache utils,并添加并传递该监听器几层在我走这条道路之前,我正在寻找信息。

2 个答案:

答案 0 :(得分:2)

http://php.net/manual/en/function.session-start.php将逐字节复制以下方法:

  

public void write(byte [] b,            int off,            int len)              抛出IOException

     

将从offset off开始的指定字节数组中的len个字节写入此输出流。   FilterOutputStream的write方法在每个要输出的字节上调用一个参数的write方法。

     

请注意,此方法不会使用相同的参数调用其基础输入流的write方法。 FilterOutputStream的子类应该提供更有效的方法实现。

答案 1 :(得分:0)

BufferedInputStreamFilterInputStream,同样适用于输出端。您可以使用它们代替过滤流并再次查看性能吗?这可能会弥补任何与IO相关的缓慢。