Java - 序列化 - EOFException问题

时间:2014-07-18 13:16:34

标签: java serialization io

对于今天关于序列化的第二篇文章感到抱歉,解决一个问题导致另一个问题。


作为州的状态 - Java - Serialization - NotSerializableException Issue - 我有一个包含以下类的项目

  

Student.java

     

StudentsCollection.java

学生创建我的学生对象(自我解释),我的StudentsCollection()实例化存储我的学生对象的学生类型列表,当我尝试保存/加载我使用此代码的对象时,抛出以下异常:

       /**
         * 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对象添加到我的列表中,在保存列表并重新打开它之后,我要求控制台打印出该列表,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)

只有一个学生对象,并在控制台中打印以下内容:

  

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

再次打印:

  

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

3 个答案:

答案 0 :(得分:2)

photoSettings.flashMode = .auto 在流的末尾不返回readObject(),因此在循环终止条件下测试它是无效的。您的代码正确在遇到流结束时抛出null。这里没有问题需要解决。

答案 1 :(得分:0)

您没有关闭输入流。我的猜测是你没有关闭输出流,而是它被截断了。使用“try-with-resource”。

      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

答案 2 :(得分:0)

问题是你的读取循环不知道要读取多少对象,所以它在文件末尾运行并获得EOFException

阅读代码执行此操作:

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

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

从查看other question开始,编写代码如下所示:

readObject

据推测,// open objectOutputStream on a file for (Student s : this.list) { objectOutputStream.writeObject(s); } list或类似的。因此可以修改编写代码:

List<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(); 个实例。