Java程序重启后读取ObjectInputStream报StreamCorruptedException求助
问题分析与解决方案
你的问题根源在于读取逻辑的循环条件错误和写入时的流头处理逻辑混乱,导致重启程序后序列化流结构损坏,触发StreamCorruptedException。
1. 核心问题点
(1)读取逻辑错误:用fis.available() > 0判断是否还有对象可读
available()方法返回的是当前输入流中可无阻塞读取的字节数,并非流中剩余的总字节数,用它来判断序列化流是否还有对象完全不可靠——它可能提前终止循环,也可能在流已读完时还返回非零值,导致读取异常。
(2)写入逻辑的流头处理错误
你当前的写入逻辑试图在文件存在时跳过流头,但实现逻辑和场景不匹配:
- 用
FileOutputStream("items.dat")默认是覆盖整个文件,此时无论文件是否存在,都应该重新写入完整的序列化流(包括合法的流头),自定义writeStreamHeader()反而会破坏流结构。 - 如果是要追加对象到已有文件,需要开启追加模式并正确跳过流头,但你的代码并没有开启追加模式,逻辑完全错位。
2. 修复后的代码
(1)正确的读取代码
循环调用readObject()直到抛出EOFException(表示流已读取完毕):
try { FileInputStream fis = new FileInputStream("items.dat"); ObjectInputStream ois = new ObjectInputStream(fis); try { // 循环读取直到流结束 while (true) { Item i = (Item) ois.readObject(); items.add(i); } } catch (EOFException e) { // 流读取完毕,正常结束 } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { ois.close(); } } catch (FileNotFoundException e) { // 文件不存在,初始化空列表 items = new ArrayList<>(); } catch (IOException e) { e.printStackTrace(); }
(2)正确的写入代码(覆盖文件场景)
使用try-with-resources语法自动管理流,每次生成完整合法的序列化流:
try (FileOutputStream fos = new FileOutputStream("items.dat"); ObjectOutputStream oos = new ObjectOutputStream(fos)) { for (Item i : items) { oos.writeObject(i); } oos.flush(); } catch (IOException e) { e.printStackTrace(); }
(3)如果需要追加对象到已有文件
开启文件追加模式,并在文件已存在时跳过流头:
boolean exists = new File("items.dat").exists(); try (FileOutputStream fos = new FileOutputStream("items.dat", true); ObjectOutputStream oos = exists ? new ObjectOutputStream(fos) { @Override protected void writeStreamHeader() throws IOException { // 跳过流头,直接追加对象 reset(); } } : new ObjectOutputStream(fos)) { for (Item i : items) { oos.writeObject(i); } oos.flush(); } catch (IOException e) { e.printStackTrace(); }
内容的提问来源于stack exchange,提问作者Dayeh
相关产品推荐
相关产品推荐

