BufferedInputStream仅在频繁小粒度读取(如逐字节read()、按行解析)时显著提升性能;对已批量读取或小文件场景反而引入开销,合理缓冲区大小需匹配读取节奏,默认8KB为通用折中值。

直接包装原始流不一定提升效率,关键看读取模式和缓冲区配置。小数据量、单次 read()、或已用 read(byte[]) 批量读取的场景,加 BufferedInputStream 反而引入额外开销。
什么时候加 BufferedInputStream 真有效
它只在「频繁调用小粒度读取」时才有明显收益,比如逐字节 read()、按行读(配合 InputStreamReader + BufferedReader)、或解析协议头等场景。
- 典型有效场景:
while ((b = bis.read()) != -1)这种循环;new BufferedReader(new InputStreamReader(bis)) - 无效甚至负优化场景:已经用
fis.read(buf, 0, buf.length)一次性读 8KB;读取总大小小于 4KB 的小文件 - 网络流特别受益:HTTP 响应体、Socket 输入流,因网络往返延迟高,缓冲能显著摊薄每次
read()的等待成本
缓冲区大小设多少才合理
默认 8192 字节(8KB)是通用折中值,但不是万能解。设太小(如 1024)会导致缓冲区频繁重填;设太大(如 1MB)会浪费内存且未必提升吞吐——操作系统和磁盘 I/O 子系统本身已有缓存层。
- 普通本地文件顺序读:4KB–8KB 足够,
new BufferedInputStream(fis, 8192) - 大文件(>100MB)或高吞吐网络流:可试 32KB–64KB,
new BufferedInputStream(fis, 32 * 1024) - 内存受限环境(如嵌入式 Java):可压到 2KB,但需实测确认性能拐点
- 避免用 0 或负数:构造时传非法大小会抛
IllegalArgumentException
容易被忽略的 close() 和 mark()/reset() 行为
BufferedInputStream 的 close() 会自动委托关闭底层流,这点常被误以为要手动关两次;但 mark() 和 reset() 依赖缓冲区容量,若读取超出 readlimit,reset() 就会失败。
- 必须确保
close()被调用,否则底层流(如FileInputStream)句柄泄露 -
mark(int readlimit)中的readlimit不是缓冲区大小,而是从 mark 位置起、reset()仍有效的最大字节数;它不能超过缓冲区实际容量 - 例如缓冲区为 8KB,但
mark(10000)后读了 9KB,再reset()就抛IOException: Resetting to invalid mark
真正影响性能的从来不是“有没有缓冲”,而是“缓冲区是否匹配你的读取节奏”。一个 64KB 缓冲区配逐字节读,和一个 2KB 缓冲区配 4KB 批量读,效果可能完全相反——得看 read() 调用频次与缓冲区填充效率的比值。


















