Input and Output with Object Files

What Java classes support input and output of objects to files?

The ObjectInputStream and the ObjectOutputStream classes are the ones you will need. You'll also need to use FileInputStream and FileOutputStream, as you did for binary and (probably) text files.

Here is a chunk of code to create a new file and set it up as the destination for subsequent object output:


ObjectOutputStream objout = new ObjectOutputStream(new FileOutputStream("mystuff.obj");
You would then use the writeObject() method of the ObjectOutputStream class to write objects to that output stream. When you are done with the output, you should invoke the close() method to close the output file.

objout.writeObject(new Integer(5));
…
objout.close();

Here is a chunk of code to create an input stream from an object file to your program for the subsequenct reading ofobjects:


ObjectInputStream objin = new ObjectInputStream(new FileInputStream("mystuff.obj");
Use the readObject() method of the ObjectInputStream class to read objects from the file. Note that the input value enters your program as something of type Object and you will need to cast it as an object of the appropriate type so that Java will let you store it's address in a reference variable of that type.

Integer i = (Integer) objin.readObject();

Are there any other tricks I should know about regarding object I/O?

Only objects that implement the Serializable interface can be written to streams. If you are outputting objects of a type you have defined, they you have to be sure that you included the "implements Serializable" phrase on the class signature. In the body of that class definition, you should have also specified an object version number using a statement such as the following


public static final long serialVersionUID = 100L;
where the actual version number (100L in the above example) is a number of your own choosing. The following is a quote from the Sun Microsystems Java API entry for the Serializable interface:
The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException. A serializable class can declare its own serialVersionUID explicitly by declaring a field named "serialVersionUID" that must be static, final, and of type long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class--serialVersionUID fields are not useful as inherited members. Array classes cannot declare an explicit serialVersionUID, so they always have the default computed value, but the requirement for matching serialVersionUID values is waived for array classes.

What if I want to output some primitive types (like ints) in addition to objects?

The ObjectInputStream and ObjectOutputStream classes have methods to support this. You can use readInt() and writeInt() methods to do int I/O with object files. There are also readDouble(), writeDouble(), readChar(), writeChar(), etc. methods to support I/O with the other primitive types. Calls to these I/O methods can interleaved with calls to readObject() or writeObject() so that you can append items to the object file in the order you choose.

Just remember that the program that does the input has to know the order in which the different object types and primitive types were outputted, because it has to follow that exact same order when inputting (or else a fatal I/O exception may be thrown).

Things to try
  1. Write a String to a text file by using System.out.println() and redirecting standard output to a file. Then output that same String, as a String object, to a file of objects using the writeObject() method of ObjectOutputStream. Compare the sizes of these two output files.

© Wiggen & Associates, 2007