请注意,以下内容仅适用于 Java 6 及更早版本。对于 Java 7 及更高版本,您应该切换到使用尝试资源...如其他答案中所述。
如果您尝试从源头捕获并报告所有异常(在 Java 6 或更早版本中),更好的解决方案是:
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(shapes);
oos.flush();
} catch (FileNotFoundException ex) {
// complain to user
} catch (IOException ex) {
// notify user
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException ex) {
// ignore ... any significant errors should already have been
// reported via an IOException from the final flush.
}
}
}
Notes:
- 标准 Java 包装器流、读取器和写入器都进行传播
close
and flush
所以你只需要关闭或刷新最外面的包装器。
- The purpose of flushing explicitly at the end of the try block is so that the (real) handler for
IOException
gets to see any write failures1.
- 当您对输出流进行关闭或刷新时,“千载难逢”的机会是由于磁盘错误或文件系统已满而引发异常。你不应该压制这个例外!.
如果您经常需要“关闭可能为空的流,忽略 IOExceptions”,那么您可以为自己编写一个如下的辅助方法:
public void closeQuietly(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException ex) {
// ignore
}
}
}
那么你可以将之前的finally块替换为:
} finally {
closeQuietly(oos);
}
另一个答案指出closeQuietly
方法已经在 Apache Commons 库中可用...如果您不介意为您的项目添加 10 行方法的依赖项。
但要小心,你只使用closeQuietly
在发生 IO 异常的流上really是无关紧要的。
UPDATE : closeQuietly
在 Apache Commons API 2.6 版本中已弃用。 Java 7+尝试资源使其变得多余。
关于问题flush()
versus close()
人们在评论中询问:
-
标准“过滤器”和“缓冲”输出流和编写器有一个 API 契约,其中规定:close()
导致所有缓冲输出被刷新。你should发现执行输出缓冲的所有其他(标准)输出类的行为方式相同。因此,对于标准类来说,调用是多余的flush()
就在之前close()
.
-
对于自定义类和第 3 方类,您需要进行调查(例如阅读 javadoc,查看代码),但是任何close()
不刷新缓冲数据的方法可以说是broken.
-
最后还有一个问题是,什么是flush()
事实上确实如此。 javadoc所说的是这样的(对于OutputStream
...)
如果该流的预期目的地是底层操作系统提供的抽象,例如文件,则刷新流只能保证之前写入流的字节被传递到操作系统进行写入;它不保证它们实际上被写入物理设备,例如磁盘驱动器。
所以...如果你希望/想象那个召唤flush()
保证您的数据将持续存在,您错了!(如果您需要做那种事情,请查看FileChannel.force
方法 ...)