Закрывает ли когда-либо IOException исключение? - PullRequest
28 голосов
/ 26 февраля 2009

После предоставления здесь некоторых ответов и чтения некоторых комментариев может показаться, что на практике IOException никогда не генерируется при закрытии для файлового ввода-вывода.

Есть ли случаи, когда при вызове close в Stream / Reader / Writer фактически генерируется IOException?

Если на самом деле выдается исключение, как с ним обращаться?

Ответы [ 5 ]

28 голосов
/ 26 февраля 2009

Я обнаружил два случая:

  • Потеря сетевого подключения, когда в буфере все еще есть данные для очистки.
  • Заполнение файловой системы (или достижение вашего пользовательского лимита для размера файла), когда в буфере еще есть данные для очистки.

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

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

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class Test
{
    public static void main(final String[] argv)
    {
        final File file;

        file = new File(argv[0]);
        process(file);
    }

    private static void process(final File file)
    {
        Writer writer;

        writer = null;

        try
        {
            writer = new FileWriter(file);
            writer.write('a');
        }
        catch(final IOException ex)
        {
            System.err.println("error opening file: " + file.getAbsolutePath());
        }
        finally
        {
            if(writer != null)
            {
                try
                {
                    try
                    {
                        System.out.println("Please press enter");
                        System.in.read();
                    }
                    catch(IOException ex)
                    {
                        System.err.println("error reading from the keyboard");
                    }

                    writer.close();
                }
                catch(final IOException ex)
                {
                    System.err.println("See it can be thrown!");
                }
            }
        }
    }
}

Начиная с Java 7 вы можете использовать try-with-resources, чтобы выйти из этого беспорядка (удален явный код генерации исключений для операции close()):

private static void process(final File file) {
    try (final Writer writer = new FileWriter(file)) {
        writer.write('a');
    } catch (final IOException e) {
        // handle exception
    }
}

это автоматически обрабатывает исключения в close() и выполняет внутреннюю проверку null.

17 голосов
/ 26 февраля 2009

Когда это происходит, с ним следует обращаться как с любым другим IOException, а не игнорировать его молча, как вы часто рекомендуете. Я предполагаю, что, поскольку вы закончили использовать поток, не имеет значения, был ли он очищен должным образом.

Однако правильная очистка очень важна. Если операция close() вызывает исключение, вероятно, она включала сброс некоторого вывода, фиксацию какой-либо транзакции (в случае подключения к базе данных, которое вы считали доступным только для чтения) и т. Д. , И, поскольку это редко, вы не значительно снижаете надежность своего приложения, прерывая операцию.

14 голосов
/ 26 февраля 2009

Для файлов вы можете не видеть, что IOException часто генерируется при close (), но вы обязательно увидите его для нефайлового ввода-вывода, например закрытия сокетов в сети.

Вот пример ошибки Java, когда закрытие UDP-сокета в конечном итоге приводило к выбросу IOException.

5 голосов
/ 26 февраля 2009

Это конкретно FileInputStream.close, который не выдает, даже если ваш жесткий диск горит. Предположительно, то же самое для ввода сокетов. Для выходных потоков вы также можете сбрасывать. До недавнего времени [см. Временные метки] BufferedOutputStream раньше не закрывал основной поток, если flush выбросил.

(@ MaartenBodewes хотел бы, чтобы я указал, что FileInputStream.close не выбрасывание не указано в документации API. На момент публикации было принято исключать пункт, в котором упоминалось, что это связано с Sun JDK (теперь известно Oracle JDK и OpenJDK. Похоже, что неясное прежнее повторное воплощение, называемое Apache Harmony, которое Android использовал для использования, могло иметь другое поведение. Потенциально другие реализации или версии OpenJDK также могут выдавать.)

3 голосов
/ 26 февраля 2009

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

...