bufferedoutputstream比fileoutputstream快,因其通过内存缓冲区(默认8192字节)批量写入,大幅减少系统调用与内核态切换次数;仅在缓冲区满、flush()或close()时才触发底层i/o,小数据高频写入时性能可提升10倍以上。

BufferedOutputStream 为什么比 FileOutputStream 快?
因为 FileOutputStream 默认每次 write() 都触发一次系统调用,而磁盘 I/O 是昂贵操作;BufferedOutputStream 在内存中维护一个字节数组缓冲区(默认 8192 字节),只有缓冲区满、调用 flush() 或 close() 时才批量写入底层流。减少系统调用次数是提速的核心逻辑。
- 小块数据频繁写入(如逐字节或短字符串循环)时,性能差距可达 10 倍以上
- 缓冲区大小不是越大越好:过大会增加内存占用,且可能因 GC 或延迟 flush 导致意外卡顿
- 注意:它不改变最终写入内容,只改变写入节奏——所以必须确保正确
close()或flush(),否则数据可能滞留缓冲区未落盘
如何正确初始化 BufferedOutputStream 提升大文件写入效率
关键在缓冲区大小和底层流的组合方式。默认 8KB 缓冲对多数场景够用,但写入超 100MB 文件时,可手动设为 64KB~256KB,并禁用 FileOutputStream 的额外缓冲(避免双重缓冲):
// ✅ 推荐:显式指定缓冲区大小,且关闭 FileOutputStream 的内部缓冲
try (FileOutputStream fos = new FileOutputStream("/path/to/large.bin", true);
BufferedOutputStream bos = new BufferedOutputStream(fos, 131072)) { // 128KB
// 写入逻辑
}
- 不要嵌套多层
BufferedOutputStream(如new BufferedOutputStream(new BufferedOutputStream(...))),这不会提速,反而增加开销 - 如果目标是追加写入(
new FileOutputStream(path, true)),确保BufferedOutputStream在追加模式下使用,否则会覆盖文件开头 - 使用 try-with-resources 自动
close(),避免忘记 flush 导致数据丢失
写入大文件时最容易丢数据的三个坑
BufferedOutputStream 的缓冲机制带来便利,也埋下静默失败风险:
- 忘记
close()或flush():程序异常退出前缓冲区未清空,最后几 KB 数据永远不写入磁盘 - 在循环中每写一次就
flush():彻底抵消缓冲价值,速度甚至比裸FileOutputStream更慢 - 把
BufferedOutputStream当作线程安全工具:它本身不是线程安全的;多线程共用同一个实例会导致数据错乱或IOException
如果必须多线程写同一文件,应改用 RandomAccessFile + 显式 seek,或用单个写线程消费队列(如 BlockingQueue<byte></byte>),而非共享 BufferedOutputStream 实例。
对比:什么时候不该用 BufferedOutputStream?
它不是万能加速器,以下场景反而有害或无效:
- 写入总量远小于缓冲区大小(比如只写 1KB),此时缓冲层纯属冗余开销
- 需要实时日志可见性(如调试日志),应直接用
PrintStream并设autoFlush=true,或手动flush() - 底层流本身已带缓冲(如某些网络 OutputStream、加密流),再套一层可能引发行为不可控(例如加密流要求严格字节边界)
- 使用 NIO 的
FileChannel+MappedByteBuffer场景:此时走内存映射路径,绕过 JVM 流体系,BufferedOutputStream完全不适用
真正影响大文件写入速度的,从来不只是“有没有缓冲”,而是“缓冲大小是否匹配 IO 模式”“是否与底层流协同”“是否被错误的 flush 节奏拖累”。这些细节一旦错位,提速就变成降速。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











