Как получить EOFException из FileInputStream - PullRequest
0 голосов
/ 24 января 2019

Я делаю проект о сжатии данных (используя алгоритм Хаффмана). Проект все еще находится в доработке. Я столкнулся с очень интересной проблемой. Мне нужно читать побайтово из двоичного файла. У меня есть файл 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();
    }
}

Но когда двоичный файл заканчивается, метод должен вернуть -1. Конечно, так и должно быть. Но есть некоторые тесты, где есть байты, которые равны -1, но не являются последними. Как вы понимаете, это действительно важно. Если в середине я прочту -1, я подумаю, что конец файла. Но это не так. Есть ли способы решить эту проблему? Могу ли я получить EOFException? И если мой код плохой, я хотел бы выслушать ваш совет.

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Проблема в том, что char не подписано, а byte подписано.В основном, где находится определенный символ (0xffff), который отображается на -1 при преобразовании в байт.Именно поэтому метод read() в InputStream возвращает целое число, даже если вы получаете байт или символ.

Один из способов решения этой проблемы - проверить, вернул ли read() -1 перед преобразованиемэто байт или символ.Затем, если read() вернет -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(), так что имейте это в виду.

0 голосов
/ 24 января 2019

Вот почему InputStream.read() объявляет тип возвращаемого значения int при фактическом чтении byte.Только младший байт int используется для данных.Если вы прочитаете -1 байт, то он вернет 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

Вы, вероятно, не хотите использовать char в своем методе public char read(), потому что char не подписан и не может содержать -1.Возвращение int и следование обычному соглашению более читабельно.

...