2014-07-18 43 views
2

对于今天第二篇关于序列化的文章,很抱歉,修复了一个问题导致了另一个问题。Java - 序列化 - EOFException问题


因为各国在这里 - Java - Serialization - NotSerializableException Issue - 我有一个项目有以下类

Student.java

StudentsCollection.java

学生创建我的学生对象(自我解释)和我的StudentsCollection()实例化一个存储我的Student对象的Student类型的列表,当试图保存/加载对象我用这个代码,并得到下面的异常抛出:

 /** 
     * Open student collection 
     */ 
     public void openCollection(){ 
      try { 
      FileInputStream e = new FileInputStream("students.ser"); 
      ObjectInputStream inputSteam = new ObjectInputStream(e); 
       while(inputSteam.readObject() != null){ 
        this.list.add((Students)inputSteam.readObject()); 
       } 
      } catch (FileNotFoundException var3) { 
       var3.printStackTrace(); 
      JOptionPane.showMessageDialog(null, "File not found"); 
      } catch (IOException var4) { 
       var4.printStackTrace(); 
      JOptionPane.showMessageDialog(null, "IO Exception"); 
      } catch (ClassNotFoundException var5) { 
       var5.printStackTrace(); 
      JOptionPane.showMessageDialog(null, "Required class not found"); 
      } 

     } 

,并投掷:

java.io.EOFException 
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2598) 
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1318) 
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370) 
    at jdatabase.objects.students.StudentsCollection.openCollection(StudentsCollection.java:558) 
    at jdatabase.main.MainController.main(MainController.java:14) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 

我只有一个Student对象添加到我的列表,保存列表之后,重新打开它,我要求控制台打印出列表,学生实际上会打印出来。但是,当我创建多个学生对象并每次将它们的ID增加1并添加它们时,控制台将打印它们全部,然后重新打印(出于某种奇怪的原因)并最终跳过几个。

如果您需要更多的代码,请询问。所述saveCollection()工作正常现在

订正代码: /**

 * Open student collection 
    */ 
    public void openCollection(){ 
     try { 
     FileInputStream e = new FileInputStream("students.ser"); 
     ObjectInputStream inputSteam = new ObjectInputStream(e); 
      while((obj = inputSteam.readObject()) != null){ 
       this.list.add((Students)obj); 
      } 
     } catch (FileNotFoundException var3) { 
      var3.printStackTrace(); 
     JOptionPane.showMessageDialog(null, "File not found"); 
     } catch (IOException var4) { 
      var4.printStackTrace(); 
     JOptionPane.showMessageDialog(null, "IO Exception"); 
     } catch (ClassNotFoundException var5) { 
      var5.printStackTrace(); 
     JOptionPane.showMessageDialog(null, "Required class not found"); 
     } 

    } 

抛出:

java.io.EOFException 
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2598) 
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1318) 
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370) 
    at jdatabase.objects.students.StudentsCollection.openCollection(StudentsCollection.java:559) 
    at jdatabase.main.MainController.main(MainController.java:13) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 

仅具有1个学生对象和下面的印刷中控制台:

学生姓名:学生 学生姓:默认 学生ID:0学生 DOB:90年1月1日

并再次印刷:

学生姓名:学生 学生姓:默认 Student ID:0 Student DoB:1/1/90

回答

1

readObject()在流结束时不返回null,因此测试它作为循环终止条件是无效的。你的代码是正确当遇到流结束时抛出EOFException。这里没有问题要解决。

+0

啊..年岁的问题。你的答案现在非常有意义,确实是*正确*。 :-) – Juxhin

-1

您没有关闭输入流。我的猜测是你没有关闭输出流,并且它正在被截断。使用“试用资源”。

 try { 
      FileOutputStream e = new FileOutputStream("students.ser"); 
      ObjectOutputStream outputStream = new ObjectOutputStream(e); 

成为

 try (
      FileOutputStream e = new FileOutputStream("students.ser") 
      ObjectOutputStream outputStream = new ObjectOutputStream(e); 
    ) { 

(编辑,以flush包装流(你不必走一路和关闭它,但它可能是最好的,而不是风险犯了一个常见的编程错误) 。)

或者你还没有写完终止null

+0

什么终止'null'? – EJP

+0

@EJP用'while(inputSteam.readObject()!= null){'读取的一个。请注意,这是一个奇怪的方案,写一些扔掉的物体来标记非终止。 –

+0

他不写一个终止null。 Ergo没有终止空。我不明白你的最后一句话。 – EJP

0

问题是您的读取循环不知道要读取多少个对象,因此它将在文件末尾运行并获取EOFException

识别代码做到这一点:

while (inputStream.readObject() != null) ... 

的问题是, readObject 从未返回null。 (来自EJP的每条评论更新)问题是readObject确实不是当它到达EOF时返回null;如果首先将null写入流,它只会返回null。因此,您无法检查空值来检测EOF。为了避免这个问题,阅读代码必须事先知道要读取多少个对象,必须以某种方式在序列化流中发送对象的数量,或者需要写入一个标记对象(或空值),指示阅读应该停止。

从看你other question,在编写代码看起来是这样的:

// open objectOutputStream on a file 
for (Student s : this.list) { 
    objectOutputStream.writeObject(s); 
} 

据推测,listList<Student>或相似。人们可以这样修改的写入的代码:

objectOutputStream.writeObject(list.size()); 
for (Student s : this.list) { 
    objectOutputStream.writeObject(s); 
} 

,然后改变读码本:

int count = (int)objectInputStream.readObject(); 
for (int i = 0; i < count; i++) { 
    this.list.add((Student)objectInputStream.readObject()); 
} 

这可能是不必要的,因为标准的集合,如ArrayList,本身是串行化的,提供他们的内容是可序列化的。由于列表中的“知道”有多少元素包含了,你没有写的次数,你可以序列化和反序列化整个列表:

objectOutputStream.writeObject(list); 

... 

@SuppressWarnings("unchecked") 
List<Student> list = (List<Student>)objectInputStream.readObject(); 

请注意,你必须压制时未检查警告反序列化,因为没有什么能够真正检查反序列化的列表实际上是否包含Student实例。

+0

非常好格式化,不能要求更好的答案。非常感谢Stuart! – Juxhin

+0

如果您写入null,则readObject()返回null。这就是null不能用作EOS指标的原因:t不是带外值。 – EJP