Search code examples
javaobjectoutputstreamobjectinputstream

Unable to read serializable class from .dat file


I try to write a keyholder, and I want to write the passwords to a .dat file using ObjectOutputStream, and then read them using ObjectInputStream. This is my code for writing the objects:

public void toFile()
{    
    try
    {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("passwords.dat"));     
        for(int i = 0; i<this.nrOfPW; i++)
        {
            if(this.PWlist[i] instanceof longPW)
            {
                oos.writeObject((longPW)this.PWlist[i]);
            }
            else
            {
                oos.writeObject((PinPW)this.PWlist[i]);
            }   
        }
        oos.close();
    }
    catch(IOException e)
    {
        e.getStackTrace();
    }
}

This seems to work, but when I try to read the file again and put the objects in my PWlist array it says that PinPW isn't serializable, even though PinPW implements Serializable and it's imported. The base class of PinPW (Info) also implements Serializable and imports it. This is the code where I read the file:

public void fromFile() 
{
    try 
    {
        ObjectInputStream objIn =  new ObjectInputStream(new FileInputStream("passwords.dat"));
        while(objIn.readObject() != null)
        {
            if(this.nrOfPW == this.PWlist.length)
            {
                expand(10);
            }
            if(objIn.readObject() instanceof PinPW)
            {
                this.PWlist[this.nrOfPW] = (PinPW)objIn.readObject();
                this.nrOfPW++;
            }
            else
            {
                this.PWlist[this.nrOfPW] = (longPW)objIn.readObject();
                this.nrOfPW++;
            }
        }
        objIn.close();
    }
    catch(EOFException e)
    {
        e.getStackTrace();
    }
    catch(IOException ex)   
    {
        ex.printStackTrace();   
    }
    catch(ClassNotFoundException ex)
    {
        ex.printStackTrace();   
    }
}

The PWlist array is a Info array, and PinPW and longPW extends Info.

What do I do to fix this problem?


Solution

  • Let's fix the "first bug, first" ...

    In this code:

    while(objIn.readObject() != null)                         // reads object, tests then *discards* it
    {
      ...
    
      if(objIn.readObject() instanceof PinPW)                 // reads object, tests then *discards* it
      {
        this.PWlist[this.nrOfPW] = (PinPW)objIn.readObject(); // conditionally read an object
        this.nrOfPW++;
      }
      else
      {
        this.PWlist[this.nrOfPW] = (longPW)objIn.readObject(); // conditionally read an object
        this.nrOfPW++;
      }
    }
    

    Each time around your loop iteration, you actually read 3 objects. The first time you read an object to check there was one in the stream, the next time you read one and determine it's type, then discard it. Then you read a third object and cast it based on what the type of the discarded object was.

    In addition, as EJP correctly points out, the correct way to determine End of Stream for an ObjectInputStream is to catch the end of file exception.

    You want to do this instead:

     try
     {
       while (true)
       {
         final Object o = objIn.readObject();            // read the object from the stream
    
         ...
    
         if (o instanceof PinPW)
         {
           this.PWlist[this.nrOfPW] = (PinPW) o;         // cast to correct type
           this.nrOfPW++;
         }
         else
         {
           this.PWlist[this.nrOfPW] = (longPW) o;        // cast to correct type
           this.nrOfPW++;
         }
       }
     }
     catch (EOFException e)
     {
       // end of stream reached ...
       // ... close the file descriptor etc ...
     }