关闭Java FileInputStream
好的,我一直在进行以下操作(变量名已更改):
FileInputStream fis = null;
try
{
fis = new FileInputStream(file);
... process ...
}
catch (IOException e)
{
... handle error ...
}
finally
{
if (fis != null)
fis.close();
}
最近,我开始使用FindBugs,这表明我没有正确关闭流。我决定看看是否可以使用finally {}块完成任何操作,然后,我明白了,哦,是的,close()会引发IOException。人们在这里应该做什么? Java库抛出太多已检查的异常。
解决方案
无论是在尝试关闭流时抛出还是吞下IOException,都应由以下操作来决定。
FileInputStream fis = null;
try
{
fis = new FileInputStream(file);
... process ...
}
catch (IOException e)
{
... blah blah blah ...
}
finally
{
try
{
if (fis != null)
fis.close();
}
catch (IOException e)
{
}
}
我们还可以使用一个简单的静态Helper方法:
public static void closeQuietly(InputStream s) {
if (null == s) {
return;
}
try {
s.close();
} catch (IOException ioe) {
//ignore exception
}
}
并从finally块中使用它。
希望有一天我们会用Java进行闭包,然后我们将失去很多冗长的细节。
因此,取而代之的是在javaIO中将有一个可以导入的辅助方法,它可能需要一个"可关闭"的接口以及一个块。在该辅助方法内,一劳永逸地定义了try {closable.close()} catch(IOException ex){// blah},然后我们就可以编写
Inputstream s = ....;
withClosable(s) {
//your code here
}
除了非常小的风格建议外,没有什么可添加的。在这种情况下,使用了自我记录代码的规范示例,为必须在close()上捕获的被忽略的IOException提供了一个描述性变量名。
squiddle的答案变成:
public static void closeQuietly(InputStream s) {
try {
s.close();
} catch (IOException ignored) {
}
}
我们主要关心的是从FindBugs获得干净的报告,还是拥有有效的代码?这些不一定是同一回事。原始代码很好(尽管我会摆脱多余的if(fis!= null)检查,因为否则会抛出OutOfMemoryException)。 FileInputStream有一个finalizer方法,如果我们在处理过程中实际收到IOException,则该方法将为我们关闭流。避免使代码更加复杂以避免极端不可能的情况是不值得的
- 你得到一个IOException和
- 这种情况经常发生,以至我们开始遇到终结器积压问题。
编辑:如果我们收到太多IOExceptions,以致终结器队列出现问题,那么我们要炸得多的鱼了!这是关于获得远见的感觉。
对于Java 7及更高版本,应使用try-with-resources:
try (InputStream in = new FileInputStream(file)) {
// TODO: work
} catch (IOException e) {
// TODO: handle error
}
如果我们坚持使用Java 6或者更低版本...
此模式避免使用null乱码:
try {
InputStream in = new FileInputStream(file);
try {
// TODO: work
} finally {
in.close();
}
} catch (IOException e) {
// TODO: error handling
}
有关如何有效处理关闭的更多详细信息,请阅读此博客文章:Java:如何避免混乱的流处理。它具有更多示例代码,更多深度,并涵盖了在catch块中进行紧密包装的陷阱。
在大多数情况下,我发现最好不要捕获IO异常,而只需使用try-finally即可:
final InputStream is = ... // (assuming some construction that can't return null)
try {
// process is
...
} finally {
is.close();
}
除了FileNotFoundException之外,我们通常无法"解决" IOException。剩下要做的唯一一件事就是报告错误,通常我们将在调用堆栈中进一步处理该错误,因此我发现更好地传播异常。
由于IOException是一个检查过的异常,因此我们必须声明此代码(及其任何客户端)抛出IOException。那可能太吵了,或者我们可能不想透露使用IO的实现细节。在这种情况下,我们可以使用异常处理程序包装整个块,该异常处理程序将" IOException"包装为" RuntimeException"或者抽象异常类型。
详细信息:我知道当finally块中的close操作产生IOException时,上述代码吞噬了try块中的任何异常。我不认为这是个大问题:通常,来自try块的异常将与导致close失败的IOException相同(即,IO正常工作然后失败的情况很少见在结束时)。如果这是一个问题,那么"沉默"关闭可能是值得的麻烦。

