views:

714

answers:

3

I am using ObjectOutputStream to create a file of serialized objects. I then use an ObjectInputStream to with the readObject() method to get the objects back out of the file.

It works great the first time. Meaning that if the file does not exist and I open it then append any number of objects, I can open the ObjectInputStream object and access all the objects.

However, if I subsequently open the same file (using the append option) and add more objects, the ObjectInputStream object gets a java.io.StreamCorruptedException: "invalid type code: AC" error where the new objects should start.

Has anyone else run into this? I even went back to some basic textbook examples from the Deitel book and still get the same error.

Edit: I found this - You may not append to the end of a serialized stream once it has been closed and reopened in append mode. The writes will appear to work, but when you go to read the file later you will get a java.io.StreamCorruptedException. at "http://mindprod.com/jgloss/gotchas.html#SERIALIZATION"

+4  A: 

Each object is serailised as part of the stream of objects, not as an individual. The "Object Stream Serialization Protocol", like most file formats (but not ZIP!) has a header. This is what every new ObjectInputStream expects to find only at the start of a file. Putting it in the middle of a stream wont work. Also the stream has backreferences, so no object is written out twice (unless otherwise specified).

So what you would need to to is create a new ObjectInputStream to match every ObjectOutputStream. There is some internal buffering, if that causes a problem you need to slice up the stream before letting Object(In|Out)putStream at it.

Tom Hawtin - tackline
There is no direct correlation between the output and input streams here. They may not even be run on the same day or workstation. One saves information to a file that at some later point another process has to open and read.
+1  A: 

If the producer and consumer of the streams are independent, it makes sense for you to just overwrite the output file each time and add a timestamp file so the consumer knows its time to reload.

For example,

SomeObject[] obj = new SomeObject[numObjects];
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("file");
out.writeObject(obj);
out.close();
long ts = System.currentTimeMillis();
ObjectOutputStream tout =
        new ObjectOutputStream(new FileOutputStream("timestamp.obj");
tout.writeObject(new Long(ts));

The consumer can then poll the timestamp.obj file every few minutes and if it has changed, reopen SomeObject[] from the stream.

ObjectInputStream in =
        new ObjectInputStream(new FileInputStream("timestamp.obj"));
Long ts = (Long)in.readObject();

if (ts > prevts) {
    ObjectInputStream in2 = new ObjectInputStream(new FileInputStream("file"));
    SomeObject[] obj = (SomeObject[])in.readObject(); 
    prevts = ts;
}
A: 

ObjectStream contains a header and footer. It also contains stateful information, i.e. what it writes is based on the objects it has already written.

Thus you cannot just append to an existing ObjectStream. What you can do is rewrite the file and add objects each time you do, or wrap the stream with your own protocol so you can write/read multiple streams correctly.

ObjectStream works best when you read/write the data with the same code base (esp. for the classes read/written) ObjectStream is not designed to be portable across versions of code or between different applications.

Peter Lawrey