如何从 FileInputStream 获取 EOFException

How to get EOFException from FileInputStream

我正在做一个关于数据压缩的项目(使用哈夫曼算法)。该项目仍在修订中。我已经 运行 遇到了一个非常有趣的问题。我需要从二进制文件中逐字节读取。我有这个文件 FileInputHelper 实现了几个方法:

import java.io.IOException;

public class FileInputHelper implements Closeable {
    private FileInputStream fileInputStream;
    private BufferedReader fileBufferedReader;

    public FileInputHelper(File file) throws IOException {
        fileInputStream = new FileInputStream(file);
        fileBufferedReader = new BufferedReader(
               new InputStreamReader(fileInputStream));
    }


    public byte readByte() throws IOException {
        return (byte)fileInputStream.read();
    }

    public char read() throws IOException {
        return (char)fileInputStream.read();
    }

    public String readLine() throws IOException {
        return fileBufferedReader.readLine();
    }

    @Override
    public void close() throws IOException{
        fileInputStream.close();
    }
}

但是当二进制文件结束时,方法应该return -1。当然,应该如此。但是有一些测试,其中有字节等于-1,但不是最后一个。 如您所知,这非常关键。如果在中间我读到 -1,我会认为文件结束了。但事实并非如此。有什么办法可以解决这个问题吗?我可以获得 EOFException 吗?如果我的代码不好,我想听听你的建议。

这就是为什么 InputStream.read() 在实际读取 byte 时声明 return 类型 int。只有 int 的低字节用于数据。如果您读取 -1 字节,那么它将 return 255 并且您必须手动将其转换为 byte.

ByteArrayInputStream in = new ByteArrayInputStream(new byte[]{1, 0, -1});
int read;
while ((read = in.read()) > -1) {
    System.out.println("As int: " + read + ", as byte: " + (byte) read);
}

即将输出:

As int: 1, as byte: 1
As int: 0, as byte: 0
As int: 255, as byte: -1

您可能不想在 public char read() 方法中使用 char,因为 char 是无符号的,不能保存 -1。返回 int 并遵循通常的约定更具可读性。

问题是 char 是无符号的,而 byte 是有符号的。基本上,当转换为字节时,映射到 -1 的特定字符 (0xffff) 在哪里。这也是为什么 InputStream 上的 read() 方法 return 是一个整数,即使您得到的是字节或字符。

处理此问题的一种方法是在将其转换为字节或字符之前检查是否 read() returned -1。然后,如果 read() 执行 return -1,您可以抛出 EOFException,并捕获它。例如,

int cur = fileInputStream.read();
if(cur == -1) {
    throw new EOFException("End of input reached");
}else {
    return (char) cur;
}

但是,捕获异常并不是指示操作已正常完成的一种方式。一种避免这种情况的处理方法是缓冲一个字符/字节,并添加一个 available() 方法,如下所示。

public class FileInputHelper implements Closeable {
    private FileInputStream fileInputStream;
    private BufferedReader fileBufferedReader;
    private int next;

    public FileInputHelper(File file) throws IOException {
        fileInputStream = new FileInputStream(file);
        fileBufferedReader = new BufferedReader(
               new InputStreamReader(fileInputStream));
        next = fileInputStream.read();
    }


    public byte readByte() throws IOException {
        int cur = next;
        next = fileInputStream.read();
        if(cur == -1) {
            throw new IOException("End of file reached");
        }
        return (byte) cur;
    }

    public char read() throws IOException {
        int cur = next;
        next = fileInputStream.read();
        if(cur == -1) {
            throw new IOException("End of file reached");
        }
        return (char) cur;
    }

    public String readLine() throws IOException {
        return fileBufferedReader.readLine();
    }

    @Override
    public void close() throws IOException{
        fileInputStream.close();
    }

    // Returns true if there are more chars / bytes to read.
    public boolean available() {
        return next != -1;
    }

}

如果您同时使用 read()/readByte()readLine() 方法,那么文件的读取方式会出现问题,因此请记住这一点。