在这里提供了一些答案并阅读了一些注释后,似乎实际上IOException永远不会在文件I/O上关闭.
是否有任何情况下,在Stream/Reader/Writer上调用close实际上会抛出IOException?
如果实际抛出异常,应如何处理?
我发现了两个案例:
当要刷新的缓冲区中仍有数据时丢失网络连接.
当缓冲区中仍有数据要刷新时,让文件系统填满(或达到文件大小的用户限制).
这两个示例都取决于缓冲区中仍有数据时发生的事情.在文件关闭之前关闭刷新缓冲区,因此如果将数据写入文件时出错,则会抛出IOException.
如果执行以下代码,将其传递给要在网络驱动器上创建的文件的名称,然后在按Enter键之前拔下网络电缆,则会导致程序在关闭时抛出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
是不扔,即使你的硬盘着火了.据推测,套接字输入是一样的.对于输出流,您也可能正在刷新.直到最近[查看时间戳] BufferedOutputStream
过去如果flush
扔掉而无法关闭底层流.
(@MaartenBodewes希望我指出FileInputStream.close
API文档没有指定不抛出.在发布时,通常会忽略提及这与Sun JDK(现在称为Oracle JDK和OpenJDK)相关的条款似乎一个名为Apache Harmony的模糊的前重新实现,Android曾经使用过它可能有不同的行为.可能还有其他实现,或者OpenJDK的版本.)