Saving and Loading Custom Objects in Java Program

1.4k views Asked by At

I am writing a small program to help with planning future workouts. I am nearly finished however saving and loading is giving me some trouble. The program works with a list of "ride"(a custom class) objects that hold a number of qualities (like a Dat, and then some ints and doubles)

right now, I have two methods, a "saver" and a "loader":

public void saver() {
        try{  // Catch errors in I/O if necessary.
            // Open a file to write to, named SavedObj.sav.
            FileOutputStream saveFile=new FileOutputStream("SaveObj.sav"); 
            // Create an ObjectOutputStream to put objects into save file.
            ObjectOutputStream save = new ObjectOutputStream(saveFile);               
            // Now we do the save.
            for (int x = 0; x < rides.size(); x++) {
                save.writeObject(rides.get(x).getDate());
                save.writeObject(rides.get(x).getMinutes());
                save.writeObject(0);
                save.writeObject(rides.get(x).getIF());
                save.writeObject(rides.get(x).getTss());
            }

            // Close the file.
            save.close(); // This also closes saveFile.
        }
        catch(Exception exc){
            exc.printStackTrace(); // If there was an error, print the info.
        }

    }

    public void loader() {
        try{
            // Open file to read from, named SavedObj.sav.
            FileInputStream saveFile = new FileInputStream("SaveObj.sav");

            // Create an ObjectInputStream to get objects from save file.
            ObjectInputStream save = new ObjectInputStream(saveFile);
            Ride worker;
            while(save.available() > 0) {
                worker = new Ride((Date)save.readObject(), (int)save.readObject(), (double)save.readObject(), (double)save.readObject(), (int)save.readObject());
                addRide(worker.getDate(), worker.getMinutes(), 0, worker.getIF(), worker.getTss());
            }

            // Close the file.
            save.close(); // This also closes saveFile.
            }
            catch(Exception exc){
                exc.printStackTrace(); // If there was an error, print the info.
        }
    }

When I run the program, neither "save" nor "load" return any errors. A .sav file is created when one does not exist, and is edited each time the program is executed. Yet, the program never restores data from previous sessions. Please let me know if more information is required. Thanks in advance for the help!

2

There are 2 answers

1
davidxxx On BEST ANSWER

Don't use available() which returns the number of bytes that can be read without blocking. It doesn't mean what all bytes were read.

If your objects are never null, you could use Object readObject() to check if all data were read from the inputstream.

Date date = null; 
while( (date = (Date)save.readObject()) != null) {
     worker = new Ride(date, (int)save.readObject(), (double)save.readObject(), (double)save.readObject(), (int)save.readObject());
     addRide(worker.getDate(), worker.getMinutes(), 0, worker.getIF(), worker.getTss());
}

Otherwise if read values may be null, you could serialize directly the Ride object or a class containing all fields to serialize rather than unitary fields which could be null
With this, the check to know if all data were read with Object readObject() could work.

0
Vampire On

Do not use available() as a condition. It just tells you whether there is some byte available for immediate reading without any delay, it does not mean the stream has reached its end.

Also you should maybe add a BufferedInputStream and BufferedOutputStream between the Object and File streams, that's almost always a good idea.

To solve your issue you could e. g. first write an integer in the save method that tells you how many objects are in the file and on load read that integer and then make a simple for loop with this amount.

Or you could throw in a PushbackInputStream in the row and then as EOF check use its read() method. It will return -1 on EOF and you can abort reading. If it returns anything else, you unread() the read byte and use the ObjectInputStream that you placed on top.