追加到对象输出流

是否不可能追加到 ?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() );
}

我不知道会有多少对象存在,所以我正在阅读,而没有例外。从谷歌的说法来看,这是不可能的。我想知道是否有人知道一种方法?


答案 1

技巧如下:子类并覆盖该方法:ObjectOutputStreamwriteStreamHeader

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

}

要使用它,只需检查历史记录文件是否存在,并实例化此可追加流(如果文件存在=我们追加=我们不需要标头)或原始流(如果文件不存在=我们需要标头)。

编辑

我对这个班级的第一个命名不满意。这个更好:它描述了“它的目的是什么”,而不是“它是如何完成的”

编辑

再次更改了名称,以阐明此流仅用于追加到现有文件。它不能用于创建包含对象数据的新文件。

编辑

在这个问题之后添加了一个调用,表明原始版本只是被覆盖为no-op,在某些情况下可能会创建无法读取的流。reset()writeStreamHeader


答案 2

API 所述,构造函数将序列化流标头写入基础流。并且此标头预计仅在文件开头出现一次。所以打电话ObjectOutputStream

new ObjectOutputStream(fos);

多次引用同一文件将多次写入标头并损坏文件。FileOutputStream