无法从.dat文件中读取可序列化的类

时间:2012-06-07 21:12:17

标签: java objectoutputstream objectinputstream

我尝试编写一个keyholder,我想使用ObjectOutputStream将密码写入.dat文件,然后使用ObjectInputStream读取它们。这是我编写对象的代码:

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();
    }
}

这似乎有效,但是当我尝试再次读取文件并将对象放入我的PWlist数组时,它说PinPW不可序列化,即使PinPW实现了Serializable并且它已导入。 PinPW(Info)的基类也实现Serializable并导入它。这是我读取文件的代码:

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();   
    }
}

PWlist阵列是一个Info数组,PinPW和longPW扩展了Info。

我该怎么做才能解决这个问题?

3 个答案:

答案 0 :(得分:1)

让我们修复“第一个错误,首先”......

在此代码中:

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++;
  }
}

每次循环迭代时,实际上都会读取 3 对象。第一次读取一个对象以检查流中是否有一个,下次读取一个并确定它的类型时,则将其丢弃。 然后你读取了第三个对象并根据被丢弃的对象的类型进行了转换。

此外,正如EJP正确指出的那样,确定ObjectInputStream的End of Stream的正确方法是捕获文件异常结束。

你想这样做:

 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 ...
 }

答案 1 :(得分:0)

你这里有问题。

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++;
        }
    }

您正在多次阅读对象。尝试保存它,然后使用它。 if(objIn.readObject()instanceof PinPW)读取一个,读取两次,this.PWlist [this.nrOfPW] =(PinPW)objIn.readObject();读三次,它应该只有一次。 PS:在一段时间内使用Greg Kopff语法而不使用final关键字,因为你想在其中保存更多对象。

答案 2 :(得分:0)

我只是想指出toFile()函数中的if-else块是完全没有意义的。 writeObject()接受Object参数。它不关心它是什么类型的对象,只要它是可序列化的。

虽然您的fromFile()方法存在严重缺陷,但不会导致NotSerializableException。我相信您所指的例外实际上发生在toFile()

原因很简单:您没有完全阅读并理解ObjectOutputStream的文档。具体而言,Object及其所有非瞬态字段和其祖先类中的所有非瞬态字段都必须实现Serializable。它还必须有一个公共的无参数构造函数。