Java中ObjectOutputStream默认不支持追加写入,因其每次构造都调用writeStreamHeader()写入重复流头导致反序列化失败;解决关键是重写该方法跳过后续写头,并配合FileOutputStream("file", true)追加模式使用,读取时仍可用标准ObjectInputStream正常解析。

Java 中 ObjectOutputStream 默认不支持追加写入(append),直接 new 一个新流去写同一个文件,会覆盖或破坏原有序列化数据结构,根本原因是每次构造都会调用 writeStreamHeader() 写入魔数和版本号(STREAM_MAGIC 和 STREAM_VERSION),而反序列化时只认第一个头 —— 后续的头会让 ObjectInputStream 报 StreamCorruptedException: invalid type code。
为什么重写 writeStreamHeader 是关键
追加写入的本质不是“接着写对象”,而是“跳过重复写头”。标准 ObjectOutputStream 在构造时强制写一次头,且该方法是 protected、可重写。只要在第二次及以后的实例中跳过写头(或改写为不写),就能让多个对象连续写入同一文件,且保持合法的序列化格式。
自定义 ObjectOutputStream 跳过重复头
继承 ObjectOutputStream,重写 writeStreamHeader(),首次写头,后续调用什么也不做。注意:必须配合 FileOutputStream 的 true 模式(即追加模式)使用。
- 构造时传入
FileOutputStream(file, true),确保字节追加到文件末尾 - 用静态标志或外部控制首次写头逻辑(推荐用构造参数明确控制)
- 不要依赖实例变量判断“是否首次”——多线程或多次 new 实例时不可靠
安全可靠的实现方式
推荐使用带参数的子类,显式指定是否写头:
立即学习“Java免费学习笔记(深入)”;
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
public class AppendableObjectOutputStream extends ObjectOutputStream {
public AppendableObjectOutputStream(OutputStream out) throws IOException {
super(out);
}
@Override
protected void writeStreamHeader() throws IOException {
// 不写头:适用于追加场景
// 若需首次写头,应在上层确保仅第一次调用此构造,并重写该方法写头
// 更稳妥做法:提供两个构造函数,或用 boolean flag 控制
}
}
实际使用时:
- 第一次写:用标准
ObjectOutputStream或自定义类中主动写头的版本 - 后续追加:用跳过
writeStreamHeader()的子类 +new FileOutputStream(file, true) - 务必保证所有写操作用同一套序列化兼容规则(如 serialVersionUID 一致)
读取时无需特殊处理
ObjectInputStream 只解析文件开头的合法头,之后按顺序读对象,不管后面有没有额外头 —— 所以你跳过写头后,整个文件仍是单个合法流,可直接用标准 ObjectInputStream 循环读取,直到抛出 EOFException。
示例读取逻辑:
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
while (true) {
try {
Object obj = ois.readObject();
// 处理 obj
} catch (EOFException e) {
break; // 正常结束
}
}
}
不复杂但容易忽略:写头逻辑和文件打开模式必须严格匹配,缺一不可。

















