【问题标题】:EOFException when reading files with ObjectInputStream [duplicate]使用 ObjectInputStream 读取文件时出现 EOFException [重复]
【发布时间】:2012-09-22 22:32:55
【问题描述】:

我基本上遇到了与此处所述类似的问题:EOFexception in Java when reading objectinputstream,但我没有找到干净代码的答案。

答案指出ObjectInputStream#readObject 将在阅读器到达文件末尾时抛出异常。在网上寻找解决方案后,我还没有找到解决方案。对于这种情况,这可能是一个好的和干净的解决方案吗?

注意:我已经尝试过了(但它看起来很难看,而且不是干净的代码)。我正在寻找更好的解决方案:

ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
try {
    Object o;
    while ((o = ois.readObject()) != null) {
        if (o instanceof MyClass) {
            MyClass m = (MyClass)o;
            //use the object...
        }
    }
} catch (EOFException eofex) {
    //do nothing
}  catch (IOException ioex) {
    throw ioex;
    //I have another try/catch block outside to control the life of the ObjectInputStream
}
//later in the code...
ois.close();

【问题讨论】:

  • 我没有发现这段代码有什么问题。我是你的文件没有对象。
  • 我的文件有对象,因为我可以在MyClass m = (MyClass)o; 行之后使用它们。它仍然抛出EOFException,我不知道如何以干净的方式摆脱它。
  • 在代码的最后会抛出这个异常,这是Java语言的基本做法。您将不得不管理该异常,这没有错
  • @BhavikAmbani 这是 this API 和其他一些 API 的“基本方法”,基本上是所有 readXXX() 方法,除了返回 readLine() 的 readLine(),以及当然read() 本身返回-1。与“Java 语言”本身无关,只是 API。
  • @downvoter:发表评论,解释您的反对意见

标签: java


【解决方案1】:

这就是应该发生的事情。你的代码是错误的。检查Javadoc。 readObject() 仅在您编写 null 时返回 null。它没有说明在 EOF 处返回空值。循环直到readObject() 返回null 才会停止,如果你曾经通过writeObject() 写过null,否则你会得到EOFException。

【讨论】:

  • 如果这应该发生,那么我可以省略 while ((o = ois.readObject()) != null) 并将其转换为 while(true),直到代码抛出 EOFException?这是唯一的出路吗?如果没有,那么请提供一些代码来理解。
  • @LuiggiMendoza 正确,就是这样做的。忽略“异常不应用于正常流量控制”工作人员的通常尖叫,因为他们只依赖于自己对“正常”的重新定义;在任何情况下,API 都不会给你任何选择。
  • 我认为这是一个非常糟糕的答案,在这个级别上不是预期的。使用 OOS 读取文件的每个级别都会引发此异常。
  • @BhavikAmbani 这个答案到底是什么“差”?如果我所说的有什么不正确的地方,请说出来。并请解释“在文件读取的每个级别”的确切含义,因为这对我来说似乎完全没有意义。如果您似乎在抱怨 API 本身而不是我的回答文本,那么您有责任说清楚。
  • @BhavikAmbani 我不认为这是一个糟糕的答案。如果这是 Java 设计人员在进行此设计时的方式,那么就没有什么可做的了。这对我来说是难过,因为我不习惯将try/catch 屏蔽作为正常行为,但我想生活中的任何事情都是第一次 :)。
【解决方案2】:

@EJP 的回答已经确定了。

但是,如果您是“不应将异常用于正常流量控制”俱乐部的付费会员*,那么您可以避免不得不赶上如果您可以使用其他方式来确定何时停止,则例外;例如

  • 您可以使用作为int 或Integer 对象发送的计数来启动流。
  • 您可以通过发送null 来标记流的结束。
  • 您可以通过发送一个表示“这是结束”的特殊对象来标记流的结束。它不需要是 MyClass 实例。
  • 您可以发送List<MyClass> ...尽管这意味着您无法“流式传输”对象。

请注意,这意味着您可以更改发送方代码...


* 成为该俱乐部的成员需要具备吸收循环论证的能力,或者愿意盲目地接受教条作为真理。 :-)


不要重复这些论点令人作呕,这里有一些链接指向我与“正常流量控制”辩论相关的一些答案:

如果你通读它们,你会发现我并没有坚定地站在栅栏的任何一边。相反,我的观点是,您应该了解权衡取舍,并根据具体情况决定例外是否合适。

【讨论】:

    【解决方案3】:

    你可以试试这个:

    boolean check=true;
    while (check) {
       try{
           System.out.println(ois.readObject());
       } catch(EOFException ex){
           check=false;
       }
    }
    

    【讨论】:

    • 欢迎来到stackoverflow。这可能会回答你的问题,但更多的解释可能会帮助其他程序员它是如何工作的。
    • 或者你可以去掉变量、初始化和赋值,并使用while (true)循环,insidetry块,然后拯救你自己几行代码和一个相当无意义且名称不佳的变量的空间。
    【解决方案4】:

    我遇到此错误是因为我忘记在写入数据的代码中关闭 ObjectOutputStream。一旦我用关闭输出流的代码再次写入数据,就可以很好地读取数据。

    【讨论】:

      【解决方案5】:

      虽然readObject() 在到达文件末尾时不会返回NULL,但如果您从一开始就控制文件,则始终可以在关闭输出流之前添加NULL。它将作为对象传递,但您可以像这样测试文件结尾:

      Boolean complete = false;
      ObjectInputStream in = <...>
      
      while(complete != true) {
          Object test = (Object)in.readObject();
          if(test != null) { someArrayList.add(test); }
              else { complete = true; }
      }
      

      【讨论】:

      • 假设“你永远不会因为任何其他原因写 null”
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-10
      • 2020-05-03
      • 1970-01-01
      • 2016-04-10
      • 1970-01-01
      • 2013-02-16
      • 1970-01-01
      相关资源
      最近更新 更多