1

我有一个对象集合:

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

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


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

ImageTransform是实现的自定义对象Serializable。所以,我相信我的地图收藏的价值部分,应该是可写的。


这是我写入文件的操作:

    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.OptionalDataExceptionat标记

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?为什么以上不起作用?

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

4

2 回答 2

3

它不起作用,因为 ObjectOutputStream 和 ObjectInputStream 写入/预期在乱序写入图像时违反了某种文件格式。要成功使用 ObjectStreams,您需要遵守 ObjectStreams 指定的合同。

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

有关更多信息,请查看有关 ObjectOutputStream的文档。

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 的实现类是否也是可序列化的。

于 2011-06-25T21:17:33.737 回答
0

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

顺便说一句 - 我倾向于使用XMLEncoder过度序列化的对象,因为它们可以在以后的 JVM 中恢复。序列化对象没有这样的保证。


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

鉴于磁盘空间非常便宜,这通常是浪费精力。

*.. 所以我想序列化更适合这个。*

不要猜测。措施。

..我会尝试使用一个列表,看看情况如何。..

凉爽的。请注意,如果使用XMLEncoder,我建议在大多数情况下将其压缩。这将减少 XML 文件的大小。这种情况在存储图像时有所不同。

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

于 2011-06-25T19:43:04.770 回答