简体   繁体   中英

How to get EOFException from FileInputStream

I am making the project about data compression(using Huffman Algorithm). The project is still in revision. I have run into very interesting problem. I need to read byte by byte from a binary file. I have got this file FileInputHelper that realize few methods:

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();
    }
}

But when the binary file end, method should return -1. Of course, it should be so. But there is some tests, where there are bytes, that are equal -1, but are not the last. As you understand, this is really critical. If in mid I read -1, I will think that there is end of the file. But it is not. Is there any ways to solve this problem? Can I get EOFException? And if my code is bad, I would like to listen your advice.

That's why InputStream.read() declares return type int when actually reading byte . Only the lower byte of int is used for data. If you read -1 byte then it will return 255 and you have to manually cast it down to 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);
}

Is going to output:

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

You probably don't want to use char in your public char read() method because char is unsigned and can't hold -1 . Returning int and following the usual convention is more readable.

The problem is that char is unsigned, while byte is signed. Basically, where is a specific character ( 0xffff ) which maps to -1 when converted to a byte. This is also why the read() method on InputStream returns an integer, even though you are getting a byte or char.

One way to handle this issue is to check if read() returned -1 before converting it to a byte or char. Then, if read() does return -1 , you can throw an EOFException, and catch that. eg,

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

However, catching exceptions is not intended as a way to indicate that an operation has completed normally. One way to handle this that avoids this is to buffer a character / byte, and add an available() method, as below.

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;
    }

}

This will have issues with how the file is read, if you use both the read() / readByte() and readLine() methods, so keep that in mind.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM