Title: ObjectOutputStream/ObjectInputStream
Course: CPS 261: Advanced Java Concepts ~ DL & MM MASTER

ObjectOutputStream / ObjectInputStream

So far, we have mostly focused on files that were text based. Now we are going to look at a few classes that
can be used for Binary.

If you want to read and write binary data (int, long, byte, char, or even classes) then consider the 2 classes:

ObjectOutputStream - An output buffering class which is passed an OutputStream as a parameter in it's constructor:

FileOutputStream fos = new FileOutputStream("someFile.dat");
ObjectOutputStream oos = new ObjectOutputStream (fos);

ObjectInputStream - An input buffering class which is passed an InputStream as a parameter in it's constructor

FileInputStream fis = new FileInputStream("someFile.dat");
ObjectInputStream ois = new ObjectInputStream(fis);

These paired classes can be used for dumping/restoring primitives and classes.

For ObjectOutputStream, we have the methods ( We should look at this in the Java API)-

- writeByte
- writeInt
- writeLong
- writeDouble
- writeUTF - for writing a String class
- ... many others

However, the most useful method of all is:

writeObject - This method allows us to write any Java class to this file in such a way that we can conveniently read it back in.
However, any class that is written with writeObject, must implement the Serializable interface.

Serializable - The Serializable interface has 0 methods (seems a little weird). Java sometimes uses Interfaces as a way to set an indication that it is OK to write this class out to an output stream.

UTF - The writeUTF and readUTF write out characters with a UTF-8 encoding. UTF-8 has become the dominant character encoding for the World Wide Web, accounting for more than half of all Web pages. Remember that Java characters need to work with all languages and hence "Unicode" is used. To deal with all of the languages in the world requires more than a million possibilities. UTF-8 accomodates this need without putting too much burden on the world of ASCII applications where each character is exactly 1 byte.

UTF-8 is backwards compatible with simple ASCII. In otherwords, if you get a UTF-8 byte which is 0 - 127, then it exactly represents an ASCII character. If you get a byte which is >= 128 then we are probably representing a character that requires 2, 3, or 4 bytes. In this case we could be representing a Chinese character.

Once you have created an ObjectOutputStream, you will want to read it back in at some point using an
ObjectInputStream which has symmetric matching methods to the ObjectOutputStream.

For example:

readByte, readInt, readLong, readDouble, readUTF, ....

And of course we need:

readObject - this allows us to read back the classes written to the ObjectOutputStream.

Casting - Since readObject returns a type of Object, you will almost always need to cast.

For example:
Horse h = (Horse) ois.readObject();

Exceptions:

In addition to the normal FileNotFoundException, and the generic IOException, you will will also encounter the exceptions:

EOFException - If the ObjectInputStream is associated with a file, you can encounter this exception when you have run out of data.

ClassNotFoundException - This exception must be caught if you call readObject. Java is trying to tell you that it couldn't find a class in the input data.

One last important point:

Although my example uses ObjectOutputStream and ObjectInputStream to write to a file and read from a file, these classes can be used in other important areas that are not related to files such as:

Internet connections - ObjectInputStream and ObjectOutputStream can be used to move classes around on the internet. We will be using these classes to make it possible to write a networked game later in the semester (your project).

Dumping and Restoring a Zoo, Snake, etc.

If you took cps161, then this example should be bring back memories of one of your assignments .... Blast from the past.


import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;


public class DumpRestore_Animals_Zoo {


    public static void main(String[] args) {
        DumpRestore_Animals_Zoo draz = new DumpRestore_Animals_Zoo();

        if (draz.dump("objectOutputStream.dat"))
            draz.restore("objectOutputStream.dat");
    }

    public boolean dump(String filename)
    {
        boolean success = true;
        Zoo myZoo = new Zoo();
        Snake sly = new Snake("Sly", 5.0 , 2, 2);
        Snake sly2 = new Snake("Slyme", 10.0 , 1, 2);
        Cow blossy = new Cow("Blossy", 900., 5,  10);
        Horse prince = new Horse("Prince", 1000., 5, 23.2);

        myZoo.add(sly);
        myZoo.add(sly2);
        myZoo.add(blossy);
        myZoo.add(prince);

        // A few extra animals not in the Zoo
        Snake jezebel = new Snake("Jezebel", 6.6, 3,3);
        Horse champ = new Horse("Champ", 1123, 7, 17.8);

        // Nothing new yet for former cps161 students

        FileOutputStream fos = null;
        ObjectOutputStream oos = null;

        try
        {
            fos = new FileOutputStream(filename);
            oos = new ObjectOutputStream(fos);

            oos.writeInt(3);  // We will be writing 3 classes
            oos.writeObject(jezebel);
            oos.writeObject(champ);
            oos.writeObject(myZoo);
        }
        catch (FileNotFoundException e)
        {
            System.out.println("dump.FileNotFoundException err: "+ e);
            success=false;
        }
        catch (IOException e)
        {
            System.out.println("dump.IOException err: "+ e);
            success=false;
        }
        finally
        {
            try
            {
                if (oos != null)
                    oos.close(); // Note this should also close fos
                else if (fos != null)
                    fos.close();
            }
            catch (IOException e)
            {
                System.out.println("dump.close IOException: It's dumb that I need to catch this exception" +e);
            }
        }

        return success;
    }

    public void restore(String filename)
    {
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        try
        {
            fis = new FileInputStream(filename);
            ois = new ObjectInputStream(fis);
            int numObjects = ois.readInt();
            /*
             I could take an approach something like
             for (int i=0; i < numObjects; i++)
             {
                 Object obj = ois.readObject();
                 ...
             }
             */

            boolean continueReading = true;

            while (continueReading)
            {
                Object obj=null;
                try
                {
                    obj = ois.readObject();
                }
                catch (EOFException e)
                {
                    System.out.println("Hit the end of the Restore file");
                    continueReading = false;
                    continue;
                }

                if (obj instanceof Zoo)
                {
                    Zoo myZoo = (Zoo)obj;
                    System.out.println("Found a zoo with the following animals ");
                    myZoo.print_all_animals();
                }
                else if (obj instanceof Snake)
                {
                    Snake snake = (Snake)obj;
                    System.out.println("Read a Snake: " + snake);
                }
                else if (obj instanceof Horse)
                {
                    Horse horse = (Horse)obj;
                    System.out.println("Read a Horse: "+ horse);
                }
            }
        }
        catch (FileNotFoundException e)
        {
            System.out.println("restore.FileNotFoundException err: "+ e);
        }
        catch (IOException e)
        {
            System.out.println("restore.IOException err: "+ e);
        }

        catch (ClassNotFoundException e)
        {
            System.out.println("restore.ClassNotFoundException: " +e);
        }

        finally
        {
            try
            {
                if (ois != null)
                    ois.close(); // Note this should also close "fis"
                else if (fis != null)
                    fis.close();
            }
            catch (IOException e)
            {
                System.out.println("restore.close IOException: It's dumb that I need to catch this exception" +e);
            }
        }
    }



}



Code provided from cps161 homework

Note that in the video, I start out without the "Serializable" changes just to show what happens when you forget to make your classes Serializable.

Zoo.java


import java.io.Serializable;


public class Zoo implements Serializable
{
    private int actual_num_animals=0;
    private int num_cages;
    private Animal[] animals;

    Zoo()
    {
        this(20);
    }
    Zoo(int num_cages)
    {
        this.num_cages = num_cages;
        animals= new Animal[num_cages];
    }

    void add(Animal a)
    {
        if (actual_num_animals < num_cages)
            animals[actual_num_animals++] = a;
        else
            System.out.println("add: Zoo overflow ... can't add animal");
    }

    double total_weight()
    {
        double total=0.0;
        for (int i=0; i < actual_num_animals; i++)
            total += animals[i].getWeight();

        return total;
    }

    void make_all_noises()
    {
        for (int i=0; i < actual_num_animals; i++)
            System.out.println( animals[i].makeNoise());
    }
    void print_all_animals()
    {
        for (int i=0; i < actual_num_animals; i++)
            System.out.println(animals[i]);

    }

}


Animal.java


import java.io.Serializable;


public abstract class Animal  implements Serializable
{
    private String name;
    private double weight;
    private int age;

    Animal()
    {
        this("No Name", 500., 1);
    }

    Animal(String n, double weight, int age)
    {
        name = n;
        this.weight = weight;
        this.age = age;
    }
    double getWeight()
    {
        return weight;
    }

    abstract String makeNoise();

    public String toString()
    {
        return name + " weight="+weight +" age="+age;
    }
}

class Cow extends Animal implements Serializable
{
    private int num_spots=1;
    Cow()
    {

    }
    Cow(String name, double weight, int age, int num_spots)
    {
        super(name, weight, age);
        this.num_spots = num_spots;
    }
    String makeNoise()
    {
        return "Mooo";
    }
    public String toString()
    {
        return super.toString() + " num spots="+num_spots;
    }

}
class Horse extends Animal  implements Serializable
{
    private double top_speed=30.0;

    Horse()
    {

    }
    Horse(String name, double weight, int age, double speed)
    {
        super(name, weight, age);
        top_speed = speed;
    }
    String makeNoise()
    {
        return "Whinny";
    }
    public String toString()
    {
        return super.toString() + " top speed="+top_speed;
    }

}


class Snake extends Animal  implements Serializable
{
    private int num_fangs=2;

    Snake()
    {

    }
    Snake(String name, double weight, int age, int num_fangs)
    {
        super(name, weight, age);
        this.num_fangs = num_fangs;
    }
    String makeNoise()
    {
        return "Hiss";
    }

    public String toString()
    {
        return super.toString() + " num fangs="+num_fangs;
    }
}



Last Updated: January 12, 2014 10:44 AM