附加到ObjectOutputStream

Ham*_*aya 55 java serialization append objectoutputstream objectinputstream

是不是可以附加到ObjectOutputStream

我试图附加到对象列表.以下代码段是一个在作业完成时调用的函数.

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

out.writeObject( new Stuff(stuff) );
out.close();
Run Code Online (Sandbox Code Playgroud)

但是当我尝试阅读它时,我只得到文件中的第一个.然后我明白了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() );
}
Run Code Online (Sandbox Code Playgroud)

我不知道会有多少个物品存在,所以我在读书时没有例外.从谷歌所说的这是不可能的.我想知道是否有人知道方法?

And*_*s_D 77

这是诀窍:子类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();
  }

}
Run Code Online (Sandbox Code Playgroud)

要使用它,只需检查历史文件是否存在,并实例化此可附加流(如果文件存在=我们追加=我们不想要标题)或原始流(如果文件不存在=我们需要一个标题).

编辑

我对班级的第一次命名感到不满意.这个更好:它描述了'它是什么'而不是'它是如何完成的'

编辑

再次更改了名称,以澄清此流仅用于附加到现有文件.它不能用于创建包含对象数据的文件.

编辑

reset()此问题之后添加了一个调用,显示刚刚覆盖writeStreamHeader为无操作的原始版本可能会在某些情况下创建无法读取的流.

  • 每个人都请注意,这只是*仅用于*附加到*现有的*文件!必须使用普通的ObjectOutputStream创建一个*new*文件,因为我们需要文件开头的标题. (4认同)
  • 显然有**这个解决方案的问题,如果你可以完全摆弄它.看看这个问题:http://stackoverflow.com/questions/12279245/classcastexception-when-appending-object-outputstream/12438141#12438141 (3认同)

Tad*_*pec 13

正如API所说,ObjectOutputStream构造函数将序列化流标头写入底层流.并且该头文件在文件的开头只有一次.所以打电话

new ObjectOutputStream(fos);
Run Code Online (Sandbox Code Playgroud)

多次在FileOutputStream指的是同一个文件会多次写入标题并破坏文件.


Mic*_*ers 7

由于序列化文件的精确格式,追加确实会破坏它.您必须将所有对象作为同一个流的一部分写入文件,否则当它在期望对象时读取流元数据时它将崩溃.

您可以阅读序列化规范以获取更多详细信息,或者(更容易)阅读此线程,其中Roedy Green基本上说的就是我刚才所说的.


Mic*_*rdt 6

避免此问题的最简单方法是在写入数据时保持OutputStream打开,而不是在每个对象之后关闭它.reset()可能建议调用以避免内存泄漏.

另一种方法是将文件读作一系列连续的ObjectInputStreams.但是这需要你计算你读取的字节数(这可以通过FilterInputStream实现),然后关闭InputStream,再次打开它,跳过那么多字节,然后将它包装在ObjectInputStream()中.