Закрывает ли когда-либо IOException?

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

Существуют ли случаи, когда вызов close на Stream/Reader/Writer действительно вызывает исключение IOException?

Если на самом деле возникает исключение, как это следует решать?

Ответ 1

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

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

Ответ 2

Я нашел два случая:

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

Оба этих примера зависят от того, что происходит, пока в буфере еще нет данных. 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 внутри.

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

Я также заметил, что PrintWriter даже не имеет предложение throws....