EOFException - как обращаться?

Я начинающий Java-программист, следуя java tutorials.

Я использую простую программу 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-уроки Страница потоков данных, it говорит:

Обратите внимание, что DataStreams обнаруживает условие конца файла, перехватывая EOFException вместо проверки на недопустимое возвращаемое значение. Все реализации методов DataInput используют EOFException вместо возвращаемых значений.

Итак, означает ли это, что catching EOFException является нормальным, поэтому просто поймать его и не обрабатывать, это хорошо, что означает, что конец файла достигнут?

Если это означает, что я должен это обработать, пожалуйста, сообщите мне, как это сделать.

ИЗМЕНИТЬ

Из предложений я исправил его, используя in.available() > 0 для условия цикла while.

Или я не мог ничего сделать, чтобы обрабатывать исключение, потому что это нормально.

Ответ 1

При чтении из файла вы не прерываете цикл. Таким образом, он читает все значения и правильно генерирует EOFException на следующей итерации чтения в строке ниже:

 price = in.readDouble();

Если вы читаете документацию, там написано:

Броски:

EOFException - если этот поток ввода достигает конца перед чтением восьми байтов.

IOException - поток был закрыт, и входящий поток не поддерживает чтение после закрытия, или происходит другая ошибка ввода-вывода.

Поместите правильное условие завершения в цикл while для решения проблемы, например, ниже:

     while(in.available() > 0)  <--- if there are still bytes to read

Ответ 2

Лучший способ справиться с этим - завершить бесконечный цикл с надлежащим условием.

Но так как вы просили об обработке исключений:

Попробуйте использовать два улова. Ожидается ваше EOFException, поэтому, кажется, нет проблем, когда это происходит. Любое другое исключение должно быть обработано.

...
} catch (EOFException e) {
   // ... this is fine
} catch(IOException e) {
    // handle exception which is not expected
    e.printStackTrace(); 
}

Ответ 3

Вы можете использовать while(in.available() != 0) вместо while(true).

Ответ 4

В качестве альтернативы вы можете сначала записать количество элементов (в виде заголовка), используя:

out.writeInt(prices.length);

Когда вы читаете файл, вы сначала читаете заголовок (количество элементов):

int elementCount = in.readInt();

for (int i = 0; i < elementCount; i++) {
     // read elements
}

Ответ 5

Вы ловите IOException, который также ловит EOFException, потому что он унаследован. Если вы посмотрите на пример из tutorial, они подчеркнули, что вы должны поймать EOFException - и это то, что они делают. Чтобы решить вашу проблему, поймайте EOFException до IOException:

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

Кроме того, мне не нравится управление потоком данных с использованием исключений - это не намеренное использование исключений и, следовательно, (на мой взгляд) действительно плохой стиль.

Ответ 6

Поместите свой код внутри блока catch try: i.e:

try{
  if(in.available()!=0){
    // ------
  }
}catch(EOFException eof){
  //
}catch(Exception e){
  //
}
}

Ответ 7

Вы можете встретить код, который читает из 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
}