Java and the Joys of Serializing Objects into RandomAccessFiles
Some bumps on the road ¶
Recently (like 5 minutes ago) I was trying to serialize an Object into a file, using the RandomAccessFile Class. After a bit of head-scratching and some google-action I found a little FAQ that apparently was determined to make my day even worse.
Now, I must admit, that I generally don’t use Java and just today had to start with it, because the professor of the lecture that I provide the tutorials for decided it was a good idea.
So I ventured out into the world of Java, armed only with my knowledge of C++syntax, my hopefully still functional brain and the good will to get things done. The FAQ gave me a first clue … using the classes ByteArrayInputStream and ByteArrayOutputStream to handle the serialized data.
Well, I’d better start at the beginning, and that is the use of RandomAccessFile, which is really no big deal.
RandomAccessFile rf = new RandomAccessFile( new File( "some.file" ), "rw" ); byte[] barry = new byte[10]; rfile.read( barry, 0, 10 );
So, as you can see the initialization is pretty straightforward and the reading of data also works the way I’d expected it to. But I wouldn’t be writing this post if there wasn’t a problem to address. It is in my understanding a problem of design of the Java API.
It all starts with the wish to serialize an Object into a RandomAccessFile and it quickly ends in dismay at the apparent shortcomings of the Java-API. The problem is, that for serialization in Java one has to use an ObjectOutputStream and the respective method writeObject( Object o ), but the ObjectOutputStream can only be initialized with an associated OutputStream which can be a FileStream. Unfortunately the RandomAccessFile class is not an OutputStream but rather more or less on the same level as ObjectOutputStream in that it in itself uses a File to write to.
The workaround is described in the aforementioned FAQ and uses a ByteArrayOutputStream for the ObjectOutputStream to write to and then converts this into an Array of Bytes and writes those to the RandomAccessFile like so:
public int writeObject( long position, Object o ) throws IOException{ m_byte_out = new ByteArrayOutputStream(); m_object_out = new ObjectOutputStream( m_byte_out ); m_object_out.writeObject( o ); m_rfile.seek( position ); //Position the Pointer m_rfile.write( m_byte_out.toByteArray() ); //Write Binary Data to File int length = m_byte_out.toByteArray().length; long length_change = ( position - m_length ) + length; if( length_change < 0 ){ length_change = 0; //Something has been overwritten, probably bad } m_length += length_change; return length; }
This function is part of a wrapper-class I have written to handle my serializable Objects in a RandomAccessFile naming it RandomAccessFileSerialized. The link is to a .jar-file containing the wrapper-class plus some tests, I uploaded those in case anyone would like to give it a try.
Well, so there it is, the basic setup as I have come up with, please comment if you think you can improve on it or see problems, I don’t claim to be a good Java programmer and this is my first Java-Project in years.
At the end, I’d like to add a word of advice, do not use this class in a production environment without prior testing, as I have done so only very briefly and can’t guarantee, that it will work as expected.
– Paul

using .NET’s streamreader, streamwriter, filestream classes can be just as counter-intuitive. LINQ helps ease the pain of xmlreader.