FileOutputStream 的 flush() 是空操作,真正确保数据落盘的是 close();推荐用 try-with-resources 自动关闭,必要时通过 FileChannel.force(true) 强制同步。

调用 flush() 和 close() 是确保 FileOutputStream 写入的数据真正写入磁盘的关键步骤。但要注意:对 FileOutputStream 来说,flush() 实际上是空操作(no-op),真正起作用的是 close() —— 它会强制刷新缓冲区并释放资源。
为什么 flush() 对 FileOutputStream 没效果
FileOutputStream 的底层实现直接写入操作系统文件句柄,不带用户态缓冲(JDK 中它继承自 OutputStream,但未重写 flush() 方法,且其内部没有缓冲区)。所以调用 flush() 不会触发任何实际写盘动作。
- 它的父类
OutputStream的flush()是空方法; - 若你包装了
BufferedOutputStream,那flush()才有意义——它会把内存缓冲区数据推到 FileOutputStream; - 单独使用 FileOutputStream 时,
flush()可省略,但close()必须调用。
close() 才是保证数据落地的核心
close() 会触发底层系统调用(如 fsync 或等效行为),确保内核缓冲区中的数据真正落盘(具体取决于操作系统和文件系统策略)。不过注意:
- Java 不保证
close()100% 同步落盘(例如 ext4 默认是“延迟写”),但已尽最大努力提交; - 若需更强持久性(如金融场景),应配合
FileChannel.force(true)使用; - 未调用
close()就退出程序,可能导致数据丢失或文件损坏。
推荐写法:用 try-with-resources 自动关闭
这是最安全、简洁的方式,编译器会自动插入 close() 调用,即使发生异常也不会遗漏:
立即学习“Java免费学习笔记(深入)”;
try (FileOutputStream fos = new FileOutputStream("data.txt")) {
fos.write("Hello".getBytes());
// 不需要显式 flush()
} catch (IOException e) {
e.printStackTrace();
}
// fos.close() 在这里自动执行
- 避免手动写
finally块,减少出错可能; - 资源在作用域结束时确定关闭,语义清晰;
- 如果中途抛异常,仍能保证关闭。
什么时候才需要额外 force 同步?
仅当业务要求“写完立刻物理落盘”(比如日志不能丢、交易凭证必须持久化)时,才需绕过内核缓冲:
- 获取 FileChannel:
fos.getChannel().force(true); -
true表示同时同步元数据(如修改时间),false仅同步数据; - 该操作较慢,不要频繁调用,按需使用即可。


















