try-with-resources中ObjectOutputStream的使用疑问:拆分构造与flush调用
关于ObjectOutputStream的两个常见疑问解答
嘿,刚好我之前也踩过类似的坑,来帮你理清楚这两个问题:
问题1:是否需要在try-with-resources中分别构造OOS和FOS?
你推测的没错,ObjectOutputStream的close()方法会自动调用底层流(也就是你的FOS)的close(),所以你当前的写法是完全可行的:
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f))) { oos.writeObject(allObjects); }
不过,也有很多开发者会选择把两个流都声明在try-with-resources里,像这样:
try (FileOutputStream fos = new FileOutputStream(f); ObjectOutputStream oos = new ObjectOutputStream(fos)) { oos.writeObject(allObjects); }
这种写法的好处是更直观——明确告诉读者:我们在管理两个资源,try-with-resources会按声明的逆序(先关OOS,再关FOS)自动关闭它们。但实际上,OOS关闭时已经会触发FOS的关闭,所以两种写法在功能上没有区别,选哪种全看团队的编码习惯。
问题2:是否需要显式调用flush方法?
正常情况下,不需要显式调用flush()。因为当try-with-resources自动关闭OOS时,OOS的close()方法会先执行flush(),把缓冲区里的所有数据写入磁盘,然后再关闭底层流。
你之前遇到的文件损坏问题,大概率不是因为没调用flush导致的,可能的原因有这些:
- 程序在OOS关闭前异常崩溃(比如突然kill进程),这时候close()没执行,缓冲区数据没写入磁盘;
- 要序列化的对象没有正确实现
Serializable接口,或者包含了非序列化的字段(且没有用transient修饰); - 写入过程中磁盘空间不足、IO错误,或者文件被其他进程篡改;
- 序列化和反序列化时的对象版本不一致(比如类结构修改后没更新serialVersionUID)。
如果你的场景需要确保数据即时写入(比如写操作后马上要读取这个文件),可以在writeObject之后显式调用oos.flush(),但这属于特殊场景的优化,不是必须的。
内容的提问来源于stack exchange,提问作者Vikron
相关产品推荐
相关产品推荐

