Java序列化追加对象报错:无效类型码AC 求修复方案及代码
问题根源
第二次追加写入时,ObjectOutputStream会自动写入序列化流头部信息,而ObjectInputStream只会识别第一个头部,后续重复的头部会被判定为无效类型码,引发"无效类型码AC"错误。另外读取时用readObject() != null判断结束是错误的——流到达末尾时会抛出EOFException,而非返回null。
修复后的写入代码
首先需要自定义一个跳过流头部的AppendableObjectOutputStream,避免追加时重复写入头部:
import java.io.IOException; import java.io.ObjectOutputStream; import java.io.OutputStream; public class AppendableObjectOutputStream extends ObjectOutputStream { public AppendableObjectOutputStream(OutputStream out) throws IOException { super(out); } // 覆盖writeStreamHeader方法,追加写入时跳过头部 @Override protected void writeStreamHeader() throws IOException { reset(); // 重置流状态,避免头部重复写入 } }
然后修改写入逻辑,判断文件是否为空:为空时用普通ObjectOutputStream写入头部,否则用自定义类追加对象:
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.util.List; public class SerializationHelper { public static void saveProducts(String filename, List<Product> productList) { File targetFile = new File(filename); boolean isFileEmpty = !targetFile.exists() || targetFile.length() == 0; try (FileOutputStream fos = new FileOutputStream(targetFile, true); ObjectOutputStream out = isFileEmpty ? new ObjectOutputStream(fos) : new AppendableObjectOutputStream(fos)) { for (Product pro : productList) { out.writeObject(pro); System.out.println(pro); } System.out.println("对象已成功保存"); productList.clear(); } catch (IOException ex) { System.out.println("捕获到IOException"); ex.printStackTrace(); } } }
修复后的读取代码
修改读取逻辑,通过捕获EOFException判断流结束,同时利用try-with-resources自动关闭流:
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.List; public class DeserializationHelper { public static List<Product> loadProducts(String filename) { List<Product> newProductList = new ArrayList<>(); try (FileInputStream file = new FileInputStream(filename); ObjectInputStream in = new ObjectInputStream(file)) { while (true) { try { Product p1 = (Product) in.readObject(); newProductList.add(p1); System.out.println(p1); System.out.println("完成读取"); System.out.println("当前列表大小: " + newProductList.size()); } catch (EOFException e) { // 捕获EOFException表示已读到文件末尾 break; } } System.out.println("已到达文件末尾。"); } catch (IOException ex) { System.err.println("读取产品数据时出错: " + ex.getMessage()); } catch (ClassNotFoundException e) { System.err.println("反序列化时找不到类: " + e.getMessage()); } return newProductList; } }
额外注意事项
Product类必须实现Serializable接口,并且保持serialVersionUID固定一致,否则反序列化会失败。- 确保每次追加写入的对象类型统一,避免反序列化时出现类型转换错误。
内容的提问来源于stack exchange,提问作者Yanuja Thanabalasingam
相关产品推荐
相关产品推荐

