加 bufferedinputstream 加速读取的关键是减少系统调用次数,而非单纯加缓冲;它通过8kb内存缓冲将百万次逐字节i/o合并为约125次批量读取,显著降低内核态切换与磁盘/网络等待开销。

加了 BufferedInputStream 后读写变快,核心不是“加了缓冲”本身,而是它把高频、小粒度的 I/O 请求,转化成了低频、大批量的系统调用——用内存换时间,用一次多读,省下十几次磁盘或网络等待。
减少系统调用,才是提速的关键
每次调用 read()(尤其是逐字节读),若没缓冲,就会触发一次操作系统级 I/O:进程切到内核态、寻道、等待磁盘响应、数据拷贝……这些开销远高于内存操作。而 BufferedInputStream 在内部维护一个字节数组(默认 8KB),只在缓冲区空时才真正调用底层流的 read(byte[]) 批量填充;后续读取全部从内存拿,毫秒级变纳秒级。
- 原始
FileInputStream.read()读 1MB 文件(逐字节)≈ 调用 100 万次系统 I/O - 套上
BufferedInputStream(8KB 缓冲)≈ 只需约 125 次批量填充 + 百万次内存访问 - 网络流更明显:一次 TCP 包往返可能耗 10~50ms,缓冲能摊薄几十次 read() 的延迟
不是所有场景都有效,匹配读取方式才重要
缓冲只对「频繁小读」起作用。如果本来就在用 read(byte[]) 批量读,再包一层反而多一层方法调用和数组拷贝,徒增开销。
- ✅ 真正受益:while ((b = bis.read()) != -1)、
BufferedReader.readLine()、协议头解析、日志行读取 - ❌ 无效甚至拖慢:已用
fis.read(buf, 0, 8192)、读取小于 4KB 的小文件、单次read()就结束的场景 - ⚠️ 网络流例外:即使你批量读,网络延迟高,缓冲仍常有收益(因重填间隔拉长,降低往返频率)
缓冲区大小不能拍脑袋定
8KB 是通用起点,但最优值取决于你的数据源、读取节奏和资源约束。设错可能让速度倒退 10 倍。
- 本地顺序读文件:4KB–8KB 足够,兼顾内存与填充效率
- 大文件(>100MB)或高吞吐 HTTP 响应:可试 32KB–64KB,减少重填次数
- 嵌入式或内存紧张环境:2KB 可接受,但必须实测确认性能拐点
- 绝对避免:0 或负数(抛
IllegalArgumentException)、盲目设 1MB(内存浪费,且 OS 层已有缓存,边际收益极低)
别忘了 mark/reset 和 close 的细节
这些行为看似边缘,但一踩坑就导致功能异常或资源泄露。
-
close()会自动关闭底层流,不用重复关——但必须调用,否则文件句柄泄漏 -
mark(int readlimit)中的readlimit不是缓冲区大小,而是从标记点起、reset()仍有效的最大偏移量;它不能超过缓冲区容量 - 例如:缓冲区 8KB,却
mark(10000)后读了 9KB,再reset()就直接抛IOException











