javaserializationappendobjectoutputstreamobjectinputstream

Appending to an ObjectOutputStream


Is it not possible to append to an ObjectOutputStream?

I am trying to append to a list of objects. Following snippet is a function that is called whenever a job is finished.

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

out.writeObject( new Stuff(stuff) );
out.close();

But when I try to read it I only get the first in the file. Then I get java.io.StreamCorruptedException.

To read I am using

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

I do not know how many objects will be present so I am reading while there are no exceptions. From what Google says this is not possible. I was wondering if anyone knows a way?


Solution

  • Here's the trick: subclass ObjectOutputStream and override the writeStreamHeader method:

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

    To use it, just check whether the history file exists or not and instantiate either this appendable stream (in case the file exists = we append = we don't want a header) or the original stream (in case the file does not exist = we need a header).

    Edit

    I wasn't happy with the first naming of the class. This one's better: it describes the 'what it's for' rather then the 'how it's done'

    Edit

    Changed the name once more, to clarify, that this stream is only for appending to an existing file. It can't be used to create a new file with object data.

    Edit

    Added a call to reset() after this question showed that the original version that just overrode writeStreamHeader to be a no-op could under some conditions create a stream that couldn't be read.