Сериализуемый на ArrayList потерять некоторые данные - PullRequest
1 голос
/ 11 марта 2019

У меня есть ArrayList объектов Employee, в которых класс Employee реализует Serializable. Я использую этот код для записи списков в файл:

ArrayList<Employee> empList = new ArrayList<>();
  FileOutputStream fos = new FileOutputStream("EmpObject.ser");
  ObjectOutputStream oos = new ObjectOutputStream(fos);
  // write object to file
  empList .add(emp1);
  empList .add(emp2);
  oos.writeObject(empList);

  empList .add(emp3);

  oos.writeObject(empList);
}

Если я пытаюсь десериализовать его, я просто получаю первые два объекта, а не третий. Может кто-нибудь попробовать, почему это так?

edit1: Если я добавляю все элементы одновременно, все в порядке, но не так, как я делал сначала. В чем разница?

ArrayList<Employee> empList = new ArrayList<>();
  FileOutputStream fos = new FileOutputStream("EmpObject.ser");
  ObjectOutputStream oos = new ObjectOutputStream(fos);
  // write object to file
  empList .add(emp1);
  empList .add(emp2);
  empList .add(emp3);
  oos.writeObject(empList);
}

После этого у меня есть 3 элемента

Ответы [ 3 ]

2 голосов
/ 11 марта 2019

Что происходит с вашим кодом:

  • вы записываете список в файл, с двумя записями
  • вы сбрасываете поток
  • вы пишете список снова, с тремя записями

Таким образом, ваш файл содержит два значения, да.Два списка, один с двумя, один с тремя записями.

Другими словами: reset() не сброс того, что было записано в файл!Вы написали один список с двумя записями.Вы только сбрасываете информацию о сохраненных объектах, так что emp1 и emp2 полностью снова сериализуют .Без вызова сброса JVM поймет, что ему не нужно снова полностью сериализовать emp1 и emp2. ​​

Значение: по умолчанию JVM сжимает объем передаваемых данных.Он запоминает, какие объекты уже были записаны, и вместо того, чтобы записывать их неоднократно, он только записывает что-то вроде «объект X, который был сериализован ранее, снова возвращается» в поток.

Итак: я думаю, вы просто не понимаете смысл метода reset().Решение: прочитайте небольшой учебник, такой как tutorialspoint .

Редактировать, учитывая последний комментарий ОП:

То, что вы просите, невозможно в этомпуть.Вы пишете список объектов.Это означает, что все записи этого списка в этот момент записываются в файл.JVM запоминает «этот список уже был написан», поэтому не запишет его снова, даже если его внутреннее состояние за это время изменилось.

1 голос
/ 11 марта 2019

Поскольку GhostCat и uaraven уже упоминали, что reset не соответствует ожиданиям, вы должны взглянуть на руководство по сериализации и, возможно, рассмотреть возможность использования sth.иначе, если это не соответствует вашему варианту использования.

Ваш код может выглядеть следующим образом при создании нового FileOutputStream:

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class SerializationTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        String path = "EmpObject.ser";

        ArrayList<Employee> empList = new ArrayList<>();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));

        empList.add(emp1);
        empList.add(emp2);
        oos.writeObject(empList);

        empList.add(emp3);
        // Create a new FileOutputStream to override the files content instead of appending the new employee list
        oos = new ObjectOutputStream( new FileOutputStream(path));
        oos.writeObject(empList);

        ObjectInputStream objectinputstream = new ObjectInputStream(new FileInputStream(path));
        List<Employee> readCase = (List<Employee>) objectinputstream.readObject();

        System.out.println(readCase);
    }
}
1 голос
/ 11 марта 2019

В основном ObjectOutputStream запоминает объекты, которые в него записаны.Если тот же объект (по ссылке) записывается снова, он не сериализуется, а ссылка на предыдущие сериализованные данные записывается в поток.Метод reset() очищает внутренние структуры данных от ObjectOutputStream и позволяет вам снова написать тот же объект.reset() не удаляет данные, уже записанные в поток.

Если вы попытаетесь десериализовать ваш поток в два ArrayLists, вы получите один с двумя элементами и один с тремя элементами.

Если вы удалите вызов метода reset(), вы получите два списка массивов с двумя элементами (один фактически сериализован, а другой - как ссылка на предыдущий сериализованный экземпляр)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...