Закрывает ли когда-либо 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....