在此处提供了一些答案并阅读了一些评论之后,似乎在实践中 IOException 永远不会在关闭文件 I/O 时抛出。
在任何情况下,在 Stream/Reader/Writer 上调用 close 实际上会引发 IOException?
如果真的抛出了异常,应该如何处理呢?
在此处提供了一些答案并阅读了一些评论之后,似乎在实践中 IOException 永远不会在关闭文件 I/O 时抛出。
在任何情况下,在 Stream/Reader/Writer 上调用 close 实际上会引发 IOException?
如果真的抛出了异常,应该如何处理呢?
我发现了两种情况:
这两个示例都取决于缓冲区中仍有数据时发生的事情。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
检查。
当它发生时,应该像其他任何事情一样处理它IOException
,而不是像你经常看到的推荐的那样默默地忽略它。我猜,假设是,既然你已经使用了流,那么它是否被正确清理并不重要。
但是,正确清理很重要。如果一个close()
操作确实引发了异常,它很可能涉及刷新一些输出、提交一些事务(在你认为是只读的数据库连接的情况下)等等——绝对不是应该忽略的事情。而且,由于这种情况很少见,因此您不会通过中止操作来显着损害应用程序的可靠性。
对于文件,您可能不会在 close() 上看到经常抛出 IOException,但您肯定会在非文件 I/O 中看到它,例如关闭到网络的套接字。
这是一个 Java 错误示例,其中关闭 UDP 套接字最终导致抛出 IOException。
FileInputStream.close
即使您的硬盘着火了,它也不会抛出异常。大概套接字输入是相同的。对于输出流,您也可能正在刷新。直到最近 [see timestamps]过去,如果抛出BufferedOutputStream
,则无法关闭底层流。flush
(@MaartenBodewes 希望我指出,FileInputStream.close
API 文档没有指定不抛出。在发帖时,习惯上省略提到这与 Sun JDK(现在称为 Oracle JDK 和 OpenJDK)有关的条款. 看起来,Android 曾经使用的一个名为 Apache Harmony 的不知名的重新实现可能有不同的行为。可能其他实现或 OpenJDK 版本也可能抛出。)
检查调用 close 时会发生什么,异常隐藏如何影响您以及您可以做些什么:博客文章。