根本原因是objectoutputstream每次新建都会写入16字节流头,导致追加时出现streamcorruptedexception;解决方法是自定义objectoutputstream,仅首次写入时调用writestreamheader(),非空文件则调用reset()跳过写头。

Java 中 ObjectOutputStream 追加写入对象时报 StreamCorruptedException: invalid type code: AC,根本原因是每次新建 ObjectOutputStream 都会往文件开头(或追加位置)写入一个 16 字节的流头(AC ED 00 05)。ObjectInputStream 只认第一个头,后续重复头会被当成非法数据,直接崩溃。
核心思路:只在首次写入时写头,追加时不写头
不能直接用 new ObjectOutputStream(new FileOutputStream("file.obj", true)),因为它的 writeStreamHeader() 方法无条件执行。必须自定义输出流,控制头是否写入。
- 判断依据是文件长度:若文件为空(
file.length() == 0),说明是首次写入,调用父类writeStreamHeader() - 若文件已存在且非空,跳过写头,改用
reset()清除内部状态,避免干扰后续对象序列化 - 注意:
reset()不清空已写入内容,只是重置 ObjectOutputStream 的内部计数器和缓存,让下一次writeObject()正常编码
推荐实现方式:匿名内部类(简洁安全)
无需单独定义新类,直接在创建流时覆盖 writeStreamHeader():
File file = new File("data.obj");
FileOutputStream fos = new FileOutputStream(file, true);
ObjectOutputStream oos = new ObjectOutputStream(fos) {
@Override
protected void writeStreamHeader() throws IOException {
if (file.length() == 0) {
super.writeStreamHeader();
} else {
reset(); // 关键:避免重复头,同时保持流可用
}
}
};
oos.writeObject(new User("Tom", 28));
oos.close();
这种写法避免了静态字段、单例管理等复杂设计,也规避了构造器中访问未初始化成员的风险。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
反序列化时不需要改动
读取仍用标准 ObjectInputStream,但要注意循环读取的写法:
- 不要依赖
available()判断——它对文件流不可靠,容易提前退出 - EOFException 作为正常结束信号
- 示例:
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data.obj"))) {
while (true) {
try {
Object obj = ois.readObject();
System.out.println(obj);
} catch (EOFException e) {
break; // 文件读完,正常退出
}
}
}
替代方案:读-改-写(适合小数据、强一致性场景)
如果对象数量不多、更新不频繁,更稳妥的方式是:
- 先全部反序列化到内存 List 中
- 添加新对象
- 一次性覆盖写回整个集合
- 优点:绝对避免头冲突,结构清晰,便于校验和备份
- 缺点:内存占用随数据量线性增长,不适合海量对象
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










