为何Java中BufferedInputStream设缓冲区大小为1却仅读取文件一次?
为什么BufferedInputStream缓冲区大小为1却只读取一次文件?
要搞懂这个问题,得先理清两个核心逻辑:BufferedInputStream的内部缓冲区作用,以及read(byte[] b)方法的行为。
关键概念拆解
- 内部缓冲区:你设置的
1是BufferedInputStream自己维护的内存块大小,它的作用是减少底层IO的调用次数——每次从底层文件流读取数据时,会尽可能填满这个缓冲区(这里就是每次读1字节)。 read(byte[] b)的行为:这个方法的目标是尽可能把你传入的byte数组填满,而不是只读取和缓冲区大小相等的数据。
你的两种场景分析
场景1:byte数组大小为1000,缓冲区大小为1
当你第一次调用b.read(does)时:
- BufferedInputStream发现内部缓冲区是空的,就从底层FileInputStream读取1字节(缓冲区大小限制)到自己的缓冲区。
- 把这1字节复制到
does数组里,此时缓冲区空了,但does还剩999字节的空间。 - 重复步骤1和2:再次从底层读1字节到缓冲区,复制到
does,直到数组被填满或者文件数据耗尽。 - 你的文件只有465字节,所以这一次
read(does)就把所有数据都读进了数组,返回值i=465。 - 进入while循环处理数据后,再次调用
read(does)时,底层流已经没有数据,返回-1,循环结束。所以你看到的x=1,是指read(does)方法只被调用了1次——但底层文件流实际被调用了465次(每次读1字节),只是BufferedInputStream帮你把这些操作合并成了一次数组读取。
场景2:byte数组大小为1,缓冲区大小为1
当你把does改成大小为1的数组时:
- 第一次调用
b.read(does),BufferedInputStream从底层读1字节到缓冲区,复制到数组后返回i=1。 - 处理完数据再次调用
b.read(does),此时缓冲区已空,就再从底层读1字节,复制到数组后返回i=1。 - 这个过程重复465次,直到文件读完,最后一次调用返回
-1,循环结束。所以x=465,也就是read(does)方法被调用了465次。
总结
- 缓冲区大小决定的是每次从底层流读取多少字节到BufferedInputStream的内部缓存,而不是每次
read方法返回的字节数。 read(byte[] b)的返回字节数,由传入的数组大小和剩余文件数据量共同决定——它会尽可能填满你的数组,直到文件读完。- 如果你想验证底层流的实际读取次数,可以自己写个继承FileInputStream的包装类,重写
read()方法并计数,就能看到缓冲区大小为1时,底层read确实被调用了465次。
内容的提问来源于stack exchange,提问作者kaka
相关产品推荐
相关产品推荐

