从文件读取对象时出现Optional Data Exception false错误,反序列化对象遇阻
从文件读取对象时出现Optional Data Exception false错误,反序列化对象遇阻
嘿,我看你在把文件里的对象读出来显示到JPanel时,卡在反序列化这一步还触发了Optional Data Exception,咱们来捋捋问题出在哪,怎么解决!
首先看你贴的保存代码,我发现一个关键问题:你直接用ImageIO.write()把背景图写入了ObjectOutputStream里,这会把序列化流的结构搞乱!
ObjectOutputStream有自己专属的序列化数据格式,而ImageIO.write()是按照PNG的原始字节格式来写数据的,两种格式混在一起之后,反序列化的时候JVM根本没法正确解析后面的Item对象,自然就抛出异常了。
另外还要提醒你:反序列化的读取顺序必须和写入顺序完全一致,哪怕顺序错了一位,也会导致数据解析失败,但现在的核心问题还是图片写入的方式不对。
给你两个可行的解决方案:
方案一:把图片转成字节数组再序列化(推荐)
修改保存时的图片写入逻辑,先把图片转成字节数组,再用ObjectOutputStream的writeObject()写入,这样就完全符合序列化流的格式了:
public static void saveFile(Screen screen) { JFileChooser find = new JFileChooser(); find.setCurrentDirectory(new File(System.getProperty("user.dir"))); int result = find.showSaveDialog(find); if(JFileChooser.APPROVE_OPTION == result) { File file = find.getSelectedFile(); try { FileOutputStream fo = new FileOutputStream(file); ObjectOutputStream os = new ObjectOutputStream(fo); os.writeInt(screen.getObjects().size()); // 把背景图转成字节数组再写入 ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(screen.getBackgroundImage(), "png", baos); byte[] imageBytes = baos.toByteArray(); os.writeObject(imageBytes); for(Item i : screen.getObjects()) { i.removeImage(); os.writeObject(i); } os.close(); fo.close(); for(Item i : screen.getObjects()) { i.setImg(); } // 剩下的异常处理代码补全 } catch (IOException e) { e.printStackTrace(); } } }
对应的读取逻辑也要改成:
// 假设读取方法里的代码 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); int itemCount = ois.readInt(); // 读取字节数组转成图片 byte[] imageBytes = (byte[]) ois.readObject(); ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes); BufferedImage background = ImageIO.read(bais); // 循环读取Item对象 List<Item> items = new ArrayList<>(); for(int i=0; i<itemCount; i++) { Item item = (Item) ois.readObject(); item.setImg(); // 恢复图片 items.add(item); } ois.close();
方案二:记录图片字节长度,分开读取(适合不想改太多代码的情况)
如果一定要用ImageIO.write()直接写,那得先把图片的字节长度写入流中,读取时先读长度,再读取对应长度的字节来解析图片,避免和后面的对象数据混淆:
保存时添加长度记录:
// 保存图片前先写入字节长度 ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(screen.getBackgroundImage(), "png", baos); byte[] imageBytes = baos.toByteArray(); os.writeInt(imageBytes.length); // 先写图片字节数 os.write(imageBytes); // 再写图片字节
读取时对应:
int imageLength = ois.readInt(); byte[] imageBytes = new byte[imageLength]; ois.readFully(imageBytes); BufferedImage background = ImageIO.read(new ByteArrayInputStream(imageBytes));
最后还要确认你的Item类是完全可序列化的:
- 必须实现
Serializable接口 - 类里所有非
transient修饰的成员变量,也都得是可序列化的(要么实现Serializable,要么是基本类型)
这样调整之后,应该就能顺利完成反序列化,把对象读取出来显示在JPanel上啦!
备注:内容来源于stack exchange,提问作者Noah Gaston
相关产品推荐
相关产品推荐

