FileInputStream 逐字节或逐块读取?

FileInputStream read byte by byte or block?

bufferedinputstream(BIS)比Why is using BufferedInputStream to read a file byte by byte faster than using FileInputStream?上提供的FileInputStream(FIS)快的原因是

With a BufferedInputStream, the method delegates to an overloaded read() method that reads 8192 amount of bytes and buffers them until they are needed while FIS read the single byte

据我了解,磁盘是 'block device'。磁盘总是会 read/write 整个块,即使读取请求是针对一些较小的数据量也是如此。 不是吗?那么 FIS 和 BIS 将如何读取完整的块而不是单个字节(如 FIS 所述)。正确的 ?那么 BIS 比 FIS 快多少?

InputStream的javaAPI就是这样。具体来说,它有这个方法:

int read() throws IOException

读取单个字节(它return是一个整数,因此它可以return -1 表示EOF)。

因此,如果您尝试从文件中读取单个字节,它会尝试这样做。对于像硬盘这样的块设备,它可能会读取整个块,然后丢弃除那个字节之外的所有内容,因此,如果您调用 read() 方法 8192 次,它会读取同一个块,一遍又一遍,8192 次,每次丢弃 8191 个字节,只给你想要的那个。这样,整个过程读取了6700万字节。哎哟。效率不高。

鉴于内核、CPU、磁盘等都以 8192 的块大小读取,BufferedInputStream(new FileInputStream)new FileInputStream 之间的性能差异为零,如果 你使用类似的东西:

byte[] buffer = new byte[8192];
in.read(buffer);

现在即使是普通的 jane 无缓冲 new FileInputStream 也只会从磁盘中读取该块一次。

BufferedInputStream 执行 'under the hood' 即使您使用 read() 的单字节形式,然后将为您提供来自该字节数组的数据以供接下来的 8191 次调用 read()。这就是 BufferedInputStream 所做的一切。

如果您使用 read()(一次一个字节)变体(或读取的字节数组变体,但使用非常小的字节数组),那么 BufferedInputStream 是有意义的。否则,那什么都不做,也没有必要把它放在那里。

注意:据我所知,java 不猜测磁盘缓冲区大小,只是使用一些合理的缓冲区大小。效果是一样的:如果一次使用一个字节,将文件流包装到缓冲流中可将性能提高 1000 倍以上,如果使用字节数组变体,则没有任何区别。