Добавление к ObjectOutputStream

Невозможно ли добавить объект ObjectOutputStream ?

Я пытаюсь добавить к списку объектов. Следующий fragment – это функция, которая вызывается всякий раз, когда задание завершено.

 FileOutputStream fos = new FileOutputStream (preferences.getAppDataLocation() + "history" , true); ObjectOutputStream out = new ObjectOutputStream(fos); out.writeObject( new Stuff(stuff) ); out.close(); 

Но когда я пытаюсь его прочитать, я получаю только первый файл. Затем я получаю java.io.StreamCorruptedException .

Чтобы читать, я использую

 FileInputStream fis = new FileInputStream ( preferences.getAppDataLocation() + "history"); ObjectInputStream in = new ObjectInputStream(fis); try{ while(true) history.add((Stuff) in.readObject()); }catch( Exception e ) { System.out.println( e.toString() ); } в FileInputStream fis = new FileInputStream ( preferences.getAppDataLocation() + "history"); ObjectInputStream in = new ObjectInputStream(fis); try{ while(true) history.add((Stuff) in.readObject()); }catch( Exception e ) { System.out.println( e.toString() ); } 

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

Вот трюк: подclass ObjectOutputStream и переопределить метод writeStreamHeader :

 public class AppendingObjectOutputStream extends ObjectOutputStream { public AppendingObjectOutputStream(OutputStream out) throws IOException { super(out); } @Override protected void writeStreamHeader() throws IOException { // do not write a header, but reset: // this line added after another question // showed a problem with the original reset(); } } 

Чтобы использовать его, просто проверьте, существует ли файл истории или нет, и создайте экземпляр этого добавочного streamа (в случае, если файл существует = мы append = нам не нужен заголовок) или исходный stream (в случае, если файл не существует = нам нужен заголовок).

редактировать

Я был недоволен первым наименованием classа. Это лучше: он описывает «что это такое», а не «как это делается»,

редактировать

Изменено имя еще раз, чтобы уточнить, что этот stream предназначен только для добавления существующего файла. Он не может быть использован для создания нового файла с данными объекта.

редактировать

Добавлен вызов reset() после того, как этот вопрос показал, что исходная версия, которая просто перестала writeStreamHeader чтобы быть не- writeStreamHeader в некоторых случаях могла создать stream, который не мог быть прочитан.

Как говорит API , конструктор ObjectOutputStream записывает заголовок streamа сериализации в базовый stream. И этот заголовок ожидается только один раз, в начале файла. Поэтому вызов

 new ObjectOutputStream(fos); 

несколько раз на FileOutputStream который ссылается на тот же файл, будет писать заголовок несколько раз и испортить файл.

Из-за точного формата сериализованного файла добавление действительно испортит его. Вы должны записать все объекты в файл как часть одного streamа, иначе он будет сбой при чтении метаданных streamа, когда он ожидает объект.

Вы можете прочитать спецификацию Serialization для более подробной информации или (проще) прочитать эту тему, где Roedy Green говорит в основном то, что я только что сказал.

Самый простой способ избежать этой проблемы – сохранить OutputStream открытым при записи данных, а не закрывать его после каждого объекта. Вызов reset() может быть целесообразным, чтобы избежать утечки памяти.

Альтернативой было бы чтение файла как серии последовательных ObjectInputStreams. Но это требует от вас подсчитать, сколько байтов вы прочитали (это может быть реализовано с помощью FilterInputStream), затем закройте InputStream, снова откройте его, пропустите это много байтов и только затем оберните его в ObjectInputStream ().

Как насчет каждого раза, когда вы добавляете объект, читаете и копируете все текущие данные в файле, а затем переписываете все вместе в файл.

Interesting Posts
Давайте будем гением компьютера.