读取文件中3个序列化对象完成后抛出java.io.EOFException问题咨询
问题根因
ObjectInputStream.readObject() 方法在读取到流末尾时不会返回null,而是直接抛出java.io.EOFException。你当前写的循环条件(o = objectInputStream.readObject()) != null永远等不到null的情况,3个对象全部读取完成后,下一次调用readObject就会触发你遇到的异常。
解决方案
以下是三种常用的修复方案,可根据业务场景选择:
方案1:捕获EOFException作为读取结束的标记
这是改动最小的方案,直接把EOFException当做读取完成的正常信号处理即可,修改后的读取代码如下:
try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file))) { while (true) { Object o = objectInputStream.readObject(); if (o.getClass().getName().contains("Plane")) { Plane plane = (Plane) o; plane.productionYear = plane.productionYearCopy; plane.speed = plane.speedCopy; plane.engine = plane.engineCopy; System.out.println(plane); } else { Ship ship = (Ship) o; ship.productionYear = ship.productionYearCopy; ship.speed = ship.speedCopy; ship.engine = ship.engineCopy; } } } catch (EOFException e) { // 属于正常读取结束,不需要打印异常 } catch (Exception e) { e.printStackTrace(); }
方案2:写入时先记录对象总数,读取时按数量读取
这种方式更规范,避免依赖异常做业务逻辑控制,需要同时修改写入和读取代码:
修改写入代码:
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file))) { planes.sort(Comparator.comparingInt(plane -> plane.productionYear)); // 先写入对象总数量 objectOutputStream.writeInt(planes.size()); planes.forEach(plane -> { try { objectOutputStream.writeObject(plane); } catch (IOException e) { e.printStackTrace(); } }); objectOutputStream.flush(); } catch (Exception e) { e.printStackTrace(); }
修改读取代码:
try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file))) { // 先读取总数量,控制循环次数 int count = objectInputStream.readInt(); for (int i = 0; i < count; i++) { Object o = objectInputStream.readObject(); if (o.getClass().getName().contains("Plane")) { Plane plane = (Plane) o; plane.productionYear = plane.productionYearCopy; plane.speed = plane.speedCopy; plane.engine = plane.engineCopy; System.out.println(plane); } else { Ship ship = (Ship) o; ship.productionYear = ship.productionYearCopy; ship.speed = ship.speedCopy; ship.engine = ship.engineCopy; } } } catch (Exception e) { e.printStackTrace(); }
方案3:写入完成后追加一个null作为结束标记
写入所有对象后额外写一个null,读取时判断到null就结束循环,也需要同时修改读写代码:
- 写入代码在
flush()之前新增一行:objectOutputStream.writeObject(null); - 读取代码不需要修改,你原来的
while ((o = objectInputStream.readObject()) != null )逻辑就可以正常工作
注意:如果你的业务场景中需要写入null作为有效对象,不要使用该方案
内容的提问来源于stack exchange,提问作者Vasil Petrovich
相关产品推荐
相关产品推荐

