Запись / чтение серии различных сериализованных объектов в / из файла - PullRequest
1 голос
/ 25 июня 2011

У меня есть коллекция предметов:

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.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 ]

3 голосов
/ 26 июня 2011

Это не работает, так как ObjectOutputStream и ObjectInputStream записывают / ожидают определенный формат файла, который нарушается, когда вы записываете изображение не по порядку.Для успешного использования ObjectStreams вам необходимо соблюдать контракт, указанный в ObjectStreams.

Для этого вам необходимо создать удерживающий класс и использовать этот класс в качестве ключа к вашей карте вместо BufferedImages.Этот удерживающий класс должен реализовывать Serializable и три метода (не в любом реальном интерфейсе), которые помечают класс как требующий специальной обработки во время чтения и записи.Подписи метода должны быть точно такими, как указано, иначе сериализация не будет работать.

Для получения дополнительной информации ознакомьтесь с документацией в 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 также сериализуем.

0 голосов
/ 25 июня 2011

Один из способов «обмануть» и иметь только один объект для сериализации - добавить группу объектов в расширяемый сериализуемый список. Затем сериализуйте список.

Кстати - я бы предпочел использовать XMLEncoder для сериализованных объектов, потому что они могут быть восстановлены в более поздних JVM. Для сериализованных Объектов такой гарантии не существует.


@ Ivan c00kiemon5ter V Kanak: "Я стараюсь сохранить файл как можно меньшего размера, ..

Это часто бесполезное усилие, учитывая, что дисковое пространство очень дешево.

* .. так что я думаю, что сериализация лучше для этого. *

Не угадай. Измерить.

.. Я попробую использовать Список и посмотрю, как это происходит. ..

Cool. Обратите внимание, что если вы используете XMLEncoder, я бы рекомендовал в большинстве случаев архивировать его. Это уменьшило бы размер файла из-за XML. Эта ситуация отличается при хранении изображений.

Форматы изображений обычно включают сжатие типа, который не способствует дальнейшему сжатию Zip. Это можно обойти, сохранив сжатый XML, а изображения как «сырые» в отдельных записях в Zip. OTOH Я думаю, что вы обнаружите, что количество байтов, сохраненных путем сжатия одного XML, не стоит усилий - учитывая окончательный размер файла записей изображения.

...