5

使用异常来指示已到达文件末尾似乎很脏。我们读取的每个文件都有一个结尾,因此它看起来并不异常或意外。此外,我不喜欢对我的程序的非异常流程使用异常。

我说的是使用java.io.EOFException来表示数据输入流的结束:

想象一个包含以下消息的文件......

----------------- ------------------
- 2-byte LENGTH - - N-byte PAYLOAD - , where N = LENGTH;
----------------- ------------------

...并使用 DataInputStream 读取此文件:

DataInputStream in = new DataInputStream(...);

...

try {
    while (true) {
        short length = in.readShort();
        byte[] b = new byte[length];
        in.readFully(b);
    }
} catch (EOFException e) { }

...

在此示例中,调用in.readShort(). 我是否应该计算出文件中的字节数,并准确读取该字节数(由total -= length归零确定),然后无一例外地退出 while 循环?我正在寻找最佳实践。

我应该做这样的事情吗?

long total = file.length();
while (total > 0) {
    short length = in.readShort();
    total -= length;
    byte[] b = new byte[length];
    in.readFully(b);
}

API 规范指定 EOFException 表示输入期间意外到达文件结尾或流结尾。但它也被数据输入流用来表示流结束。

当出现例外情况时我该怎么办?

4

3 回答 3

2

方法参考API规范DataInput.readFully

 This method blocks until one of the following conditions occurs:

    * b.length bytes of input data are available, in which case a normal return is made.
    * End of file is detected, in which case an EOFException is thrown.
    * An I/O error occurs, in which case an IOException other than EOFException is thrown.

所以这个想法是它要么读取 b.length 字节的数据,要么如果它不能这样做,你会得到一个错误,要么是因为 I/O 错误,要么是在读取 b.length 字节之前到达文件结尾。

因此,您应该在调用之前知道要读取多少字节DataInput.readFully。如果超出文件末尾,则被认为是异常行为,因此,这就是您获得异常的原因。

于 2010-07-27T16:03:22.840 回答
1

您提到了通常给出的建议,即异常应仅用于发出异常事件的信号。这个建议的问题在于它用另一个不确定性(“什么时候抛出异常”)替换了另一个不确定性(“什么是异常的”)。

一个不同且更好的答案是,当且仅当替代方案是无法建立后置条件或维持不变量时,您应该抛出异常。

对输入流执行读取操作的后置条件是已成功读取值。显然,如果我们处于 EOF,则无法读取任何值。所以必须抛出某种类型的异常。调用代码想要停止读取,所以它必须是一种独特的异常类型(不是一般的 IOException)。因此,需要一个特定的 EOFException。

另一种方法是读取操作没有成功读取作为后置条件。这就是 C (POSIX) API 所做的。实际上,每个读取操作实际上都是一次尝试读取操作。然后阅读器代码需要检查状态代码以查看读取尝试是否实际成功。这种代码风格难以理解、冗长且容易出错。使用异常而不是状态代码的动机之一是避免这些困难。

于 2016-03-25T17:16:09.510 回答
0

顾名思义,readFully当您希望完全读取一些已知长度的字节时使用。如果之前达到 EOF,那是出乎意料的,然后在概念上抛出异常是正确的。如果您想要read语义,请使用read方法。

于 2010-07-27T16:07:35.783 回答