应使用 bufferedinputstream/bufferedoutputstream 包装 fileinputstream/fileoutputstream 以减少系统调用;读写须批量操作,避免逐字节循环;缓冲区大小需按场景调整,大文件可考虑零拷贝。

直接用 FileInputStream 或 FileOutputStream 逐字节读写,每次调用都会触发系统调用,频繁访问磁盘导致性能明显下降。加一层 BufferedInputStream 或 BufferedOutputStream,相当于在内存里建了个“中转站”,数据批量进出,大幅减少底层 IO 次数,这是最简单也最有效的优化手段。
正确封装方式:必须包装,不能裸用
缓冲流是装饰器,必须套在基础流外面,不能单独创建:
- 读文件:用
FileInputStream → BufferedInputStream包装,后续read()优先从内存缓冲区取数据,仅当缓冲区空时才触发底层批量填充 - 写文件:用
FileOutputStream → BufferedOutputStream包装,数据先暂存在缓冲区,满或显式刷新时才真正落盘 - 避免逐字节循环:不要用
while ((b = bis.read()) != -1)处理大文件,改用带字节数组的read(byte[])批量读取,效率更高
缓冲区大小设置要分场景
默认 8KB(8192 字节)只是通用起点,不是最优解:
- 小文件(
- 大文件顺序读写(如日志归档、媒体拷贝):建议设为 32KB 或 64KB,降低
fill()调用次数,提升吞吐量 - 高并发服务(如文件网关):单流缓冲不宜过大,推荐 8–16KB,兼顾内存占用与吞吐
- 内存受限环境(如嵌入式或容器资源限制):避免设到几百 KB,缓冲区全在堆内存中,易引发 GC 压力
flush 和 close 的时机不能靠猜
BufferedOutputStream 的数据不会立刻写入磁盘,而是等缓冲区满、显式 flush() 或 close() 时才真正输出:
- 用
try-with-resources最稳妥:它会在退出时自动调用close(),而close()内部会先flush() - 需要中间结果可见(如实时日志、关键状态写入),必须在关键节点手动
flush(),不能只依赖close() - 别在写完就立即
close()又马上打开——频繁开关流抵消缓冲收益,应复用流实例
哪些情况其实不需要缓冲流
不是所有 IO 都适合加缓冲:
- 数据量极小(比如只读几个字节或写固定 header),加缓冲反而多一层对象开销和方法调用
- 对延迟极度敏感且数据必须立刻落盘(如金融交易指令),缓冲可能引入不可控延迟,此时需绕过缓冲直写,配合
getChannel().force(true) - 已用 NIO 的
FileChannel+MappedByteBuffer(适用于 >100MB 文件),其“零拷贝”机制比传统缓冲流更高效,无需再套BufferedOutputStream
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











