java - 为什么使用 FilterOutputStream 拦截 FileInputStream 到 FileOutputStream 的传输要慢几个数量级?

标签 java jvm fileinputstream fileoutputstream

上下文

我正在尝试在数据传输期间获取反馈。会发生不同的情况,但我正在处理的特定情况是 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 的实现,以免影响测试),复制 450Mb 文件的时间从 5-10 秒直线下降(没有 FilterOutputStream 包装)大约 8 分钟。

一些事实

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

问题

为什么会出现这种情况?有什么办法可以解决这个问题吗?

我猜测 JVM 能够检测文件复制的标准模式并将其直接委托(delegate)给操作系统。对我来说有点奇怪的是,它会在 Buffered 流中执行此操作,但无法通过 FilterOutputStream 间接的 write 方法执行此操作。

目前我看到的唯一解决方法是在复制循环中实现一个监听器,而不是通过管道输出流,但因为这需要重新实现循环而不是使用 Apache utils,并添加该监听器并向下传递几层关于 API,我在走这条路之前正在寻找信息。

最佳答案

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

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

Writes len bytes from the specified byte array starting at offset off to this output stream. The write method of FilterOutputStream calls the write method of one argument on each byte to output.

Note that this method does not call the write method of its underlying input stream with the same arguments. Subclasses of FilterOutputStream should provide a more efficient implementation of this method.

关于java - 为什么使用 FilterOutputStream 拦截 FileInputStream 到 FileOutputStream 的传输要慢几个数量级?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37446021/

相关文章:

java - 如何通过 ProcessBuilder 在 Java 中调用 CUDA C 应用程序?

java - 打开Android App按钮不会返回到当前已打开的Activity

java - 当 JVM 终止时停止线程并将映射保存到磁盘

java - Java中的字符序列化、BufferedReader

java - 如何计算android中四个不同gps坐标点之间的面积

java - 本地成员更快或实例成员

Java 条件运算符速度与 Hotspot VM 版本

java - OutOfMemoryError - 如何在 hprof 创建后终止 JVM

java - 如何比较两个文件是否相同?

java - 在这种情况下,为 BufferedInputStream 调用 available() 会导致我误入歧途吗?