关闭Java FileInputStream

时间:2020-03-06 14:57:51  来源:igfitidea点击:

好的,我一直在进行以下操作(变量名已更改):

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正常工作然后失败的情况很少见在结束时)。如果这是一个问题,那么"沉默"关闭可能是值得的麻烦。