Search this site

 Home  I/O  Buffering  Character streams  NIO intro  Buffers  Channels  Buffer performance

Search this site:
Threads Database Profiling Regular expressions Random numbers Compression Exceptions C Equivalents in Java

 What do you think of this article? Did it help you? Found a mistake? Feedback and suggestions here

StreamCorruptedException

A Java StreamCorruptedException can be thrown while deserialising data. It essentially occurs in one of two main cases:

  • you try to open an ObjectInputStream around some data that wasn't actually written using an ObjectOutputStream;
  • during a readObject() operation, the stream gets in the "wrong place".

Essentially, what happens is that, somehow or other, the writing and the reading get "out of kilter". Here are a couple of ways it can happen:

Forgetting to close the ObjectOutputStream that wrote the data (or closing the wrong stream)

If I had a dollar for every time I'd seen this mistake, I'd be typing this article on a more expensive laptop. The mistake usually looks something like this:

OutputStream out = new FileOutputStream(f);
BufferedOutputStream bout = new BufferedOutputStream(out);
ObjectOutputStream oout = new ObjectOutputStream(bout);
oout.write(object);
out.close();

The problem here is that we've closed the wrong stream. In between the actual FileOutputStream and the object writing, there is a layer of buffering. Thus, when we close the underlying output stream, there is a risk that some of the data is still "stuck" in the buffer.

The solution is simple, and is how you should always handle closing streams: ALWAYS close the stream that was created last, in this case, the ObjectOutputStream. This way, each layer of streaming has a chance to pass any buffered data down to the stream below it (and by definition, the close() method must do so). Note that you don't need to close every stream— just the outer one.

Forgetting to check the return value of InputStream.read().

This is also a mistake I've seen time and time again. It happens when you're manually chopping up an input stream into sections and then passing part of the stream to an ObjectInputStream. Each section might be preceded by a four-byte length marker, for example:

public Object readObject(InputStream in) throws IOException, ... {
  int objDataLen = readInt(in);
  byte[] objData = new byte[objDataLen];
  in.read(objData);
  ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(objData));
  return oin.readObject();
}

Here, our capital sin is that we assume that the read() method will fill the array. It won't necessarily, and we end up with a partial object stream. The problem can be especially difficult to track down when the bytes are coming in over a network, because the problem will be intermittent and essentially random.

If this problem occurs at some point in the stream, then it will have a knock-on effect on later parts of the stream. The solution is to be careful to always check the return value of InputStream.read() when reading into an array.

comments powered by Disqus

Written by Neil Coffey. Copyright © Javamex UK 2012. All rights reserved.