FileInputStream是按字节读取还是按字节读取?

2019年10月19日 26点热度 0条评论

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

使用BufferedInputStream,该方法将委托给重载
read()方法,读取8192个字节并对其进行缓冲,直到
在FIS读取单个字节时需要它们

据我了解,磁盘是一个“块设备”。即使读取请求只需要少量数据,磁盘仍将始终读取/写入整个块。
是不是?因此,即使FIS和BIS都将如何读取完整的块而不是单个字节(如针对FIS所述)。对 ?那么BIS如何比FIS更快?

解决方案如下:

InputStream的Java API就是它。具体来说,它具有以下方法:

int read() throws IOException

它读取一个字节(它返回一个int,以便它可以返回-1表示EOF)。

因此,如果您尝试从文件中读取单个字节,它将尝试这样做。对于像硬盘这样的块设备,它很可能会读取整个块,然后丢弃除一个字节之外的所有内容,因此,如果调用
read()方法8192次,它将读取相同的块,然后结束了8192次,每次都剔除8191个字节并只提供您想要的字节。因此,在整个过程中读取6700万字节。哎哟。不是很有效。

假设内核,CPU,磁盘等全部读取的块大小为8192,则
BufferedInputStream(new FileInputStream)
new FileInputStream之间的性能差异为零,如果使用的是以下内容:

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

现在,即使是简·简·无缓冲的
new FileInputStream最终也只能从磁盘读取一次该块。

即使您使用
BufferedInputStream的单字节形式,
read()也会在后台执行此操作,然后会将该字节数组中的数据提供给
read()的下一次8191调用。这就是
BufferedInputStream的全部工作。

如果您使用的是
read()(一次一个字节)变体(或read的字节数组变体,但字节数组很小),那么
BufferedInputStream是有意义的。否则,它什么都不做,也没有必要将其放入其中。

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