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

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

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

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() );
}

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

5 ответов


вот трюк: подкласс 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();
  }

}

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

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

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

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

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

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

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


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

new ObjectOutputStream(fos);

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


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

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


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

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


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