You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从文件读取对象时出现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 12:49:50