BufferedInputStream 比 FileInputStream 快,因其通过内存缓冲(默认8192字节)减少系统调用和内核态切换;实操建议:小文件可不使用缓冲,大文件务必使用。

BufferedInputStream 为什么比 FileInputStream 快?
因为 FileInputStream 每次 read() 都触发一次系统调用,而 BufferedInputStream 在内存里预读一块数据(默认 8192 字节),后续读取直接从缓冲区拿,大幅减少内核态切换次数。
实操建议:
- 不要对小文件(
- 如果已知数据块大小较固定(如每次读 1024 字节),可显式指定缓冲区大小:
new BufferedInputStream(in, 1024) - 注意:
mark()/reset()依赖缓冲区容量,超出readlimit后reset()会抛IOException
BufferedOutputStream flush() 不调用就丢数据?
是的。BufferedOutputStream 的 write 操作只是往内存缓冲区写,不立即落盘;close() 会自动 flush(),但若中途异常退出且没 close(),缓冲区里最后那截数据就丢了。
常见错误现象:
立即学习“Java免费学习笔记(深入)”;
- 程序写完没报错,但文件内容比预期少几字节
- 用
try-with-resources时,提前return导致close()没走完(实际不会——JVM 保证执行,但容易误判)
实操建议:
- 在关键写入后主动调用
flush(),比如日志行输出、协议头写完 - 避免在循环内频繁
flush()——每调一次都是系统调用,性能反降 - 缓冲区大小影响明显:默认 8192 字节,写入总量远小于它时,
flush()几乎无代价;接近或超限时,才真正触发write()系统调用
BufferedInputStream + BufferedOutputStream 组合使用要注意什么?
它们本身不感知对方存在,但组合用于文件拷贝等场景时,缓冲策略会叠加影响实际 I/O 行为。
使用场景:
- 文件复制、资源打包、网络响应体中转
- 不是所有场景都适合——比如实时音频流需要低延迟,大缓冲反而增加首帧等待时间
容易踩的坑:
- 两端缓冲区大小不匹配:例如
BufferedInputStream用 4KB,BufferedOutputStream用 64KB,可能导致中间数据在内存“卡住”更久 - 未处理流关闭顺序:必须先关
out再关in,否则out.close()可能阻塞在等待更多输入 - 别包装两次:对同一个
FileInputStream套两层BufferedInputStream,第二层缓冲纯属冗余,还多占内存
Java 9+ 的 Files.copy() 为啥不推荐手动套 Buffer?
因为 Files.copy(InputStream, OutputStream) 内部已经做了优化:它检测到源/目标是 FileChannel 时会走零拷贝(transferTo/transferFrom);否则才用带缓冲的循环读写,默认缓冲区 8192 字节,和手写 BufferedInputStream + BufferedOutputStream 效果一致。
所以:
- 直接用
Files.copy()更简洁,且 JVM 未来可能进一步优化底层路径 - 只有需要自定义读写逻辑(如跳过 BOM、解密、限速)时,才值得自己控制缓冲流
- 注意:
Files.copy()不会自动创建父目录,FileNotFoundException可能来自路径不存在,而非权限问题
缓冲的本质是空间换时间,但“换多少”得看数据规模、访问模式和系统负载——这些没法靠加一层类名带 Buffered 就自动搞定。










