【发布时间】:2018-09-15 06:54:29
【问题描述】:
首先,我理解缓冲作为包装器的概念,例如,FileInuptStream 充当从底层流读取内容(让我们读取场景)的临时容器,在这种情况下 - @987654323 @。
- 比如说,有 100 个字节要从流中读取(文件作为源)。
- 如果没有缓冲,代码(
BufferedInputStream的read方法)必须进行 100 次读取(一次一个字节)。 - 使用缓冲,根据缓冲区大小,代码进行
- 假设缓冲区大小为 50。
- 因此,代码仅读取缓冲区(作为源)两次以读取文件的内容。
- 现在,由于
FileInuptStream是数据(包含100 个字节的文件)的最终来源(虽然被BufferedInputStream包装),所以它不是必须读取100 次才能读取100 个字节吗?虽然,代码调用了BufferedInputStream的read方法,但是调用传递给FileInuptStream的read方法,需要进行100 次读取调用。这是我无法理解的一点。
IOW,虽然被BufferedInputStream 包裹,但底层流(例如FileInputStream)仍然必须一次读取一个字节。那么,缓冲的好处在哪里(不是只需要两次读取调用来缓冲的代码,而是应用程序的性能)?
谢谢。
编辑:
我将此作为后续的“编辑”而不是“评论”,因为我认为它的上下文更适合这里,并且作为 TL;DR 供@Kayaman 和我之间聊天的读者使用。
BufferedInputStream 的read 方法说(摘录):
为了方便起见,它 通过反复调用 底层流的读取方法。这种反复阅读继续 直到满足以下条件之一:
The specified number of bytes have been read, The read method of the underlying stream returns -1, indicating end-of-file, or The available method of the underlying stream returns zero, indicating that further input requests would block.
我深入研究了代码,发现方法调用跟踪如下:
-
BufferedInputStream->read(byte b[])作为一个我想看到缓冲的作用。 -
BufferedInputStream->read(byte b[], int off, int len) -
BufferedInputStream->read1(byte[] b, int off, int len)- 私人的 -
FileInputStream- 读取(字节 b[],int 关闭,int len) -
FileInputStream->readBytes(byte b[], int off, int len)- 私有和原生。来自源代码的方法描述 -
将子数组作为字节序列读取。
在BufferedInputStream 中调用read1(上面提到的#4)处于无限for 循环中。它返回上述read 方法描述摘录中提到的条件。
正如我在 OP(#6) 中提到的,调用似乎是由与 API 方法描述和方法调用跟踪匹配的底层流处理的。
问题仍然存在,如果原生 API 调用 - FileInputStream 的 readBytes 一次读取一个字节并创建一个包含这些字节的数组以返回?
【问题讨论】:
-
这太棒了。我说的第一件事是“FileInputStream 不必一次读取一个字节”,方法的名称是
readBytes,末尾有一个 S 表示复数。但是您仍然一直说它一次读取一个字节。为什么要讨论“它会这样做吗?” “不,它没有” “但是……如果它这样做了怎么办?”。 -
我将编辑您的问题以指出您的示例逻辑中有哪些问题。如果您不想要它,我将回滚更改。现在完全错了,也许你对你写的东西感到困惑,这只是你的错误猜测。
-
1.这是一个方法名称,在内部,它可以对硬盘上的文件进行多次读取(一次一个字节)并创建一个要返回的数组。 2.我没猜,我是按照API方法描述和源代码挖掘去的。
-
如果底层流(如 FileInputStream)确实提供批量读/写(实际上是由本机调用处理的),那么,如果有错误,请纠正我,
BufferedInputStream只是一个类似帮助器的对象管理内存中的内容。否则,代码必须自己管理标记、重置或任何其他有效机制。 -
那么现在你终于明白了!?当所有大众媒体、文件系统和其他一切都在块中处理事情时,您的行为是假设事情一次完成 1 个字节。
标签: java buffer bufferedinputstream