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

我不知道有多less物体会出现,所以我正在阅读,而没有例外。 从谷歌说这是不可能的。 我想知道有没有人知道一个方法?

这里的技巧:子类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(如果文件存在=我们追加=我们不想要一个头)或原始stream(万一文件不存在=我们需要一个标题)。

编辑

我对class级的第一个命名感到不高兴。 这个更好:它描述了“它是为了什么”而不是“如何完成”

编辑

再次更改名称,澄清此stream只用于附加到现有的文件。 它不能用于创build具有对象数据的文件。

编辑

在这个问题之后,增加了一个调用reset() , 这个问题表明,只是将writeStreamHeader为空操作的原始版本可能会在某些情况下创build一个无法读取的stream。

如API所示 , ObjectOutputStream构造函数将序列化stream头写入基础stream。 这个头文件在文件的开始部分预计只有一次。 所以打电话

 new ObjectOutputStream(fos); 

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

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

你可以阅读序列化规范了解更多细节,或者(更容易)阅读这个主题 ,Roedy Green基本上是这样说的。

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

另一种方法是将文件作为一系列连续的ObjectInputStreams读取。 但是这需要你保持计数你读的字节数(这可以用FilterInputStream来实现),然后closuresInputStream,再打开它,跳过那么多字节,然后把它包装在一个ObjectInputStream()中。

如何在每次添加对象之前,读取并复制文件中的所有当前数据,然后一起覆盖文件。