Почему я должен беспокоиться об IOExceptions, когда файл закрыт?

Я часто вижу подобное в коде Java...

try
{
    fileStream.close();
}
catch (IOException ioe)
{
    /* Ignore. We do not care. */
}

Является ли это разумным или кавалером?

Когда мне будет интересно, что закрытие файла не удалось? Каковы последствия игнорирования этого исключения?

Ответ 1

Я бы, по крайней мере, регистрировал исключение.

Я видел, как это случалось иногда, если попытка закрыть файл не удалась из-за того, что он не смог очистить данные. Если вы просто проглотите исключение, вы потеряете данные, не осознавая этого.

В идеале вам следует, вероятно, усвоить исключение, если вы уже находитесь в контексте другого исключения (т.е. вы находитесь в блоке finally, но из-за другого исключения, а не завершения блока try), но бросьте его, если ваш в противном случае операция будет успешной. К сожалению, это несколько уродливо, чтобы разобраться: (

Но да, вы должны хотя бы зарегистрировать его.

Ответ 2

Вам будет интересно, если метод close() сбрасывает написанное содержимое из буфера в файловую систему, и это терпит неудачу. например если файл, который вы пишете, находится в удаленной файловой системе, которая стала недоступной.

Обратите внимание, что вышеперечисленное. flushing применяется к любому выходному потоку, а не только к файлам.

Ответ 3

Наиболее распространенными проблемами close() являются свободное место на диске или, как упоминал Брайан, удаленный поток, который удалил пуф.

Примечание:

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

SomeKindOfStream stream = null;
Throwable pending = null;
try {
    stream = ...;
    // do stuff with stream

} catch (ThreadDeath t) {
    // always re-throw thread death immediately
    throw t;

} catch (Throwable t) {
    // keep track of any exception - we don't want an exception on
    //   close() to hide the exceptions we care about!
    pending = t;

} finally {
    if (stream != null)
        try {
            stream.close();
        } catch (IOException e) {
            if (pending == null)
                pending = e;
        }
    }
    if (pending != null) {
        // possibly log - might log in a caller
        throw new SomeWrapperException(pending);
          // where SomeWrapperException is unchecked or declared thrown
    }
}

Почему все это?

Имейте в виду, что Java может отслеживать только одно "ожидающее" исключение за раз. Если тело основного блока try генерирует исключение, и, то close() в итоге генерирует исключение, единственное, о чем вы узнаете, это close().

Вышеупомянутая структура делает следующее:

  • Следите за любым броском, брошенным в тело try.
  • Если это исключение - это смерть потока, немедленно снимите его!
  • При закрытии, если у нас нет ожидающего исключения, отследите закрытое исключение; в противном случае следует отслеживать предыдущее исключение. (Вероятно, вы должны попытаться зарегистрировать ошибку close() в этом случае)
  • В конце, если есть незавершенное исключение, справитесь с ним. Я обычно обертываю его и реконструирую. Лично я использую непроверенную оболочку, поэтому мне не нужно, чтобы все вызывающие в цепочке вызовов объявляли броски.

Чтобы сделать это, я обычно использую шаблон метода шаблона для создания управления исключениями и затем переопределяю метод doWork(), который является телом try.