能否在不重复新建ObjectOutputStream的前提下将其输出拆分到多个文件
解决方案
Java原生ObjectOutputStream的重复对象检测、循环引用处理能力是绑定在流实例本身的缓存上的,只要不重建实例,缓存就会持续生效。所以你只需要给ObjectOutputStream套一层可动态切换底层输出目标的代理输出流,就可以在不新建ObjectOutputStream的前提下,把不同主题的数据写入不同文件。
具体实现步骤
1. 实现可动态切换目标的代理输出流
import java.io.IOException; import java.io.OutputStream; public class SwitchableOutputStream extends OutputStream { private OutputStream currentOut; // 切换底层输出目标 public void switchTarget(OutputStream newOut) { this.currentOut = newOut; } @Override public void write(int b) throws IOException { if (currentOut != null) { currentOut.write(b); } } @Override public void write(byte[] b) throws IOException { if (currentOut != null) { currentOut.write(b); } } @Override public void write(byte[] b, int off, int len) throws IOException { if (currentOut != null) { currentOut.write(b, off, len); } } @Override public void flush() throws IOException { if (currentOut != null) { currentOut.flush(); } } // close方法仅需在所有序列化完成后调用一次 @Override public void close() throws IOException { if (currentOut != null) { currentOut.close(); } } }
2. 序列化使用示例
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class SplitSerializationDemo { public static void main(String[] args) throws IOException { // 初始化可切换代理流 SwitchableOutputStream switchableOut = new SwitchableOutputStream(); // 全程仅创建一次ObjectOutputStream,复用实例缓存 ObjectOutputStream oos = new ObjectOutputStream(switchableOut); // 写入玩家数据到player.dat try (FileOutputStream playerOut = new FileOutputStream("player.dat")) { switchableOut.switchTarget(playerOut); oos.writeObject(playerInstance); // 替换为你的玩家数据对象 oos.flush(); } // 写入世界数据到world.dat,跨对象的引用检测依然生效 try (FileOutputStream worldOut = new FileOutputStream("world.dat")) { switchableOut.switchTarget(worldOut); oos.writeObject(worldInstance); // 替换为你的世界数据对象 oos.flush(); } // 写入敌人数据到enemy.dat try (FileOutputStream enemyOut = new FileOutputStream("enemy.dat")) { switchableOut.switchTarget(enemyOut); oos.writeObject(enemyListInstance); // 替换为你的敌人数据集合 oos.flush(); } // 所有主题数据写完后再关闭流 oos.close(); } }
注意事项
- 序列化全程不要调用
ObjectOutputStream#reset()方法,否则会清空实例内部的引用缓存,丢失重复对象检测能力 - 反序列化时需要使用相同逻辑:创建同一个
ObjectInputStream实例,套可切换的代理输入流,严格按照序列化时的文件顺序依次读取各个文件的内容,才能正确还原跨文件的对象引用 - 每个文件写完后只需要调用
flush(),不要提前关闭ObjectOutputStream,直到所有主题文件都写完再执行关闭操作
内容的提问来源于stack exchange,提问作者blafexe
相关产品推荐
相关产品推荐

