向/从文件写入/读取一系列不同的序列化对象

时间:2011-06-25 19:22:40

标签: java image file serialization read-write

我有一组对象:

Map<BufferedImage, Map<ImageTransform, Set<Point>>> map

我想将它们写入文件,然后能够在同一个结构中读回它们。


我不能按原样编写集合,因为BufferedImage没有实现Serializable(也不是Externalizable)接口。所以我需要使用ImageIO类中的方法来编写图像。

ImageTransform是一个实现Serializable的自定义对象。所以,我相信我的地图集合中的 value 部分应该是可写的。


以下是我对文件所做的工作:

    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
    for (BufferedImage image : map.keySet()) {
        ImageIO.write(image, "PNG", out);  // write the image to the stream
        out.writeObject(map.get(image));   // write the 'value' part of the map
    }

以下是我从文件中读取所做的工作:

    ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
    while(true) {
        try {
            BufferedImage image = ImageIO.read(in);
            Map<ImageTransform, Set<Point>> value = 
                (Map<ImageTransform, Set<Point>>) in.readObject(); // marker
            map.put(image, value);
        } catch (IOException ioe) {
            break;
        }
    }

然而,这不起作用。我在标记处获得了java.io.OptionalDataException

java.io.OptionalDataException
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1300)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)

我的问题是,首先,写作概念是否正确? ImageIO#write对于这种情况有用,还是应该考虑使用/存储BufferedImage#getRgb int[]数组?数组是否更紧凑(如在文件中占用更少的空间)? 其次,我应该如何从文件中读取对象?我如何知道何时达到EOF?为什么上面的工作没有?

我希望提供的信息足够,如果您需要更多信息,请告诉我 提前致谢。

2 个答案:

答案 0 :(得分:3)

它不起作用,因为ObjectOutputStream和ObjectInputStream写入/期望在您按顺序写入图像时违反某种文件格式。要成功使用ObjectStream,您需要观察ObjectStreams指定的契约。

要执行此操作,您需要创建一个保持类,并使用此类作为地图的键而不是BufferedImages。此保持类应实现Serializable和三种方法(不在任何实际接口中),这些方法将Class标记为在读取和写入期间需要特殊处理。方法签名必须完全符合指定,否则序列化将无效。

有关详细信息,请查看ObjectOutputStream上的documentation

public class ImageHolder implements Serializable {

    BufferedImage image;

    public ImageHolder(BufferedImage image) {
        this.image = image;
    }

    private void readObject(ObjectInputStream stream) 
            throws IOException, ClassNotFoundException {
        image = ImageIO.read(stream);
    }

    private void writeObject(ObjectOutputStream stream) 
            throws IOException {
        ImageIO.write(image, "PNG", stream);
    }

    private void readObjectNoData() throws ObjectStreamException {
        // leave image as null
    }

然后连续出版应该像outputStream.writeObject(map)一样简单。虽然您需要检查ImageTransform的实现类是否也是可序列化的。

答案 1 :(得分:0)

“欺骗”并且只有一个对象可以序列化的一种方法是将对象组添加到可扩展的可序列化列表中。然后序列化列表。

BTW - 我倾向于使用XMLEncoder而不是序列化的对象,因为它们可以在以后的JVM中恢复。序列化对象没有这样的保证。


  

@Ivan c00kiemon5ter V Kanak:“我正在努力保持文件尽可能小,..

考虑到磁盘空间非常便宜,这往往是浪费精力。

  

* ..所以我猜序列化对此更好。 *

不要猜。测量

  

..我会尝试使用List,看看情况如何。 ..

冷却。请注意,如果使用XMLEncoder,我建议在大多数情况下使用它。这将减少XML的文件大小。这种情况在存储图像方面是不同的。

图像格式通常包含不利于Zip进一步压缩的类型的压缩。这可以通过存储压缩的XML来进行,也可以将图像作为“原始”存储在Zip中的单独条目中。 OTOH我认为你会发现通过单独压缩XML节省的字节数是不值得的 - 考虑到图像条目的最终文件大小。