24

我是一名学习Java 教程的初学者 Java 程序员。

我正在使用Java 教程数据流页面中的一个简单的 Java 程序,并且在运行时,它一直在显示EOFException。我想知道这是否正常,因为读者最终必须到达文件的末尾。

import java.io.*;

public class DataStreams {
    static final String dataFile = "F://Java//DataStreams//invoicedata.txt";

    static final double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 };
    static final int[] units = { 12, 8, 13, 29, 50 };
    static final String[] descs = {
        "Java T-shirt",
        "Java Mug",
        "Duke Juggling Dolls",
        "Java Pin",
        "Java Key Chain"
    };
    public static void main(String args[]) {
        try {
            DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile)));

            for (int i = 0; i < prices.length; i ++) {
                out.writeDouble(prices[i]);
                out.writeInt(units[i]);
                out.writeUTF(descs[i]);
            }

            out.close(); 

        } catch(IOException e){
            e.printStackTrace(); // used to be System.err.println();
        }

        double price;
        int unit;
        String desc;
        double total = 0.0;

        try {
            DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(dataFile)));

            while (true) {
                price = in.readDouble();
                unit = in.readInt();
                desc = in.readUTF();
                System.out.format("You ordered %d" + " units of %s at $%.2f%n",
                unit, desc, price);
                total += unit * price;
            }
        } catch(IOException e) {
            e.printStackTrace(); 
        }

        System.out.format("Your total is %f.%n" , total);
    }
}

它编译得很好,但输出是:

You ordered 12 units of Java T-shirt at $19.99
You ordered 8 units of Java Mug at $9.99
You ordered 13 units of Duke Juggling Dolls at $15.99
You ordered 29 units of Java Pin at $3.99
You ordered 50 units of Java Key Chain at $4.99
java.io.EOFException
        at java.io.DataInputStream.readFully(Unknown Source)
        at java.io.DataInputStream.readLong(Unknown Source)
        at java.io.DataInputStream.readDouble(Unknown Source)
        at DataStreams.main(DataStreams.java:39)
Your total is 892.880000.

Java 教程Data Streams Page,它说:

请注意,DataStreams 通过捕获EOFException来检测文件结束条件,而不是测试无效的返回值。DataInput 方法的所有实现都使用 EOFException 而不是返回值。

那么,这是否意味着捕获EOFException是正常的,所以只是捕获它而不处理它就可以了,这意味着到达了文件末尾?

如果这意味着我应该处理它,请告诉我如何去做。

编辑

根据建议,我通过使用in.available() > 0forwhile循环条件修复了它。

或者,我无法处理异常,因为这很好。

4

8 回答 8

24

从文件中读取时,您并没有终止循环。因此,它读取所有值并在下一次读取迭代中正确抛出 EOFException 如下行:

 price = in.readDouble();

如果您阅读文档,它会说:

抛出:

EOFException - 如果此输入流在读取八个字节之前到达末尾。

IOException - 流已关闭且包含的输入流在关闭后不支持读取,或者发生另一个 I/O 错误。

在您的 while 循环中放置适当的终止条件以解决问题,例如:

     while(in.available() > 0)  <--- if there are still bytes to read
于 2013-08-26T19:13:29.320 回答
7

处理此问题的最佳方法是在适当的条件下终止无限循环。

但是由于您要求进行异常处理:

尝试使用两个捕获。您的 EOFException 是预期的,因此它发生时似乎没有问题。应处理任何其他异常。

...
} catch (EOFException e) {
   // ... this is fine
} catch(IOException e) {
    // handle exception which is not expected
    e.printStackTrace(); 
}
于 2013-08-26T19:17:54.573 回答
2

您可以使用while(in.available() != 0)而不是while(true).

于 2013-08-26T19:14:40.680 回答
2

或者,您可以使用以下方法先写出元素的数量(作为标题):

out.writeInt(prices.length);

读取文件时,首先读取标题(元素计数):

int elementCount = in.readInt();

for (int i = 0; i < elementCount; i++) {
     // read elements
}
于 2013-08-26T19:24:04.313 回答
2

您可能会遇到从 an 读取InputStream并使用代码段 while(in.available()>0)检查流结尾的代码,而不是检查 EOFException(文件结尾)。

这种技术的问题,并且Javadoc确实回应了这一点,它只告诉您可以读取的块数,而不会阻塞下一个调用者。换句话说,return 0即使有更多字节要读取,它也可以。因此,InputStream available()永远不应该使用该方法来检查流的结束。

您必须使用while (true)

catch(EOFException e) {
//This isn't problem
} catch (Other e) {
//This is problem
}
于 2018-12-08T13:43:20.027 回答
0

你 catchIOException也可以 catch EOFException,因为它是继承的。如果您查看教程中的示例,他们强调您应该抓住EOFException- 这就是他们所做的。为了解决你EOFException之前的问题IOException

try
{
    //...
}
catch(EOFException e) {
    //eof - no error in this case
}
catch(IOException e) {
    //something went wrong
    e.printStackTrace(); 
}

除此之外,我不喜欢使用异常进行数据流控制——这不是异常的预期用途,因此(在我看来)非常糟糕的风格。

于 2013-08-26T19:22:05.697 回答
0

将您的代码放在 try catch 块中:即:

try{
  if(in.available()!=0){
    // ------
  }
}catch(EOFException eof){
  //
}catch(Exception e){
  //
}
}
于 2017-01-18T12:02:56.340 回答
0

EOFException 是 IOException 的孩子,我更喜欢下面的 ==>

try {
        .
        .
        .
    } catch (IOException e) {
        if (!(e instanceof EOFException)) {
            throw new RuntimeException(e);
        }
    }
于 2021-06-13T15:40:27.747 回答