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

Why is intercepting a FileInputStream to FileOutputStream transfer with FilterOutputStream orders of magnitude slower?

上下文

我正在尝试在数据传输过程中获得反馈。会出现不同的情况,但我正在处理的特殊情况是 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]);

现在,当我这样做时,删除了实际的 "do something"(在上面的示例中,删除了我使用基本 FilterOutputStream 的实现,以免影响测试),复制一个 450Mb 的文件从5-10 秒(没有 FilterOutputStream 换行)到大约 8 分钟。

几个事实

问题

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

我猜测 JVM 能够检测文件复制的标准模式并将其直接委托给 OS。这对我来说似乎有点奇怪,它将包装在缓冲流中,但不能用 FilterOutputStream 间接的写入方法来做到这一点。

现在我看到的唯一解决方法是在复制循环中直接实现一个监听器而不是管道输出流,但因为这需要重新实现循环而不是使用 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.

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