关闭Java FileInputStream
好的,我一直在做以下工作(变量名已更改):关闭Java FileInputStream,java,exception,stream,Java,Exception,Stream,好的,我一直在做以下工作(变量名已更改): 最近,我开始使用FindBugs,这表明我没有正确地关闭流。我决定看看是否有什么可以用finally{}块来完成,然后我看到,哦,是的,close()可以抛出IOException。人们应该在这里做什么?Java库抛出太多已检查的异常。类似于以下内容的操作应该可以做到这一点,这取决于您在尝试关闭流时是否抛出或吞下IOException FileInputStream fis = null; try { fis = new FileInputSt
最近,我开始使用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)
{
}
}
您还可以使用简单的静态帮助器方法:
public static void closeQuietly(InputStream s) {
if (null == s) {
return;
}
try {
s.close();
} catch (IOException ioe) {
//ignore exception
}
}
从finally块中使用它。希望有一天我们会在Java中得到闭包,然后我们会失去很多详细信息 因此,取而代之的是一个助手方法,在javaIO中,您可以导入它,它可能需要一个“可关闭”接口和一个块。在这个helper方法中,try{closable.close()}catch(IOException ex){//blah}是一次性定义的,然后您就可以编写
Inputstream s = ....;
withClosable(s) {
//your code here
}
没有什么要补充的,除了一个非常小的风格建议自文档化代码的典型示例在本例中适用-为被忽略的
IOException
提供一个描述性变量名,您必须抓住close()
斯奎德尔的答案是:
public static void closeQuietly(InputStream s) {
try {
s.close();
} catch (IOException ignored) {
}
}
您主要关心的是从FindBugs获得一个干净的报告,还是拥有可以工作的代码?这些不一定是同一件事。您的原始代码很好(尽管如果(fis!=null)检查时,我会去掉冗余的
,因为如果不是这样,就会抛出OutOfMemoryException
)。FileInputStream有一个终结器方法,它将在处理过程中实际收到IOException时为您关闭流。为了避免极不可能发生的错误,不值得费心让代码更复杂
你得到一个IOException,然后
这种情况经常发生,以至于您开始遇到终结器积压问题
编辑:如果您遇到太多IOException,以致于在终结器队列中遇到问题,那么您将面临更大的麻烦!这是关于获得透视感。对于Java 7及以上版本,应使用:
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
}
有关如何有效处理close的更多详细信息,请阅读以下博文:。它有更多的示例代码,更深入,并且覆盖了在catch块中封装close的陷阱。在大多数情况下,我发现捕获IO异常比捕获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
或抽象异常类型
详细信息:我知道当块中的关闭
操作最终产生IOException时,上述代码会从try
块中吞下任何异常。我不认为这是一个大问题:通常,来自try
块的异常与导致close
失败的IOException
是同一个。如果这是一个问题,那么可能值得费心“静默”关闭。如果关闭失败,下面的解决方案会正确抛出异常,而不会在关闭前隐藏可能的异常
try {
InputStream in = new FileInputStream(file);
try {
// work
in.close();
} finally {
Closeables.closeQuietly(in);
}
} catch(IOException exc) {
// kernel panic
}
这是因为第二次调用close
这依赖于番石榴,但如果愿意,可以编写自己的方法,如所示(另请参见)
在一般情况下,报告close错误非常重要,因为close可能会向流写入一些最终字节,例如由于缓冲。因此,您的用户想知道它是否失败,或者您可能想采取某种行动。当然,在FileInputStream的特定情况下,这可能不是真的,我不知道(但由于前面提到的原因,我认为如果发生关闭错误,最好报告关闭错误)
由于嵌入式try块的结构,上面的代码有点难以理解。有两种方法可能会更清楚,一种是抛出IOException,另一种是捕获IOException。至少我会选择这样
private void work() throws IOException {
InputStream in = new FileInputStream(file);
try {
// work
in.close();
} finally {
Closeables.closeQuietly(in);
}
}
public void workAndDealWithException() {
try {
work();
} catch(IOException exc) {
// kernel panic
}
}
基于(由McDowell引用)。您可以使用添加的JDK7功能。它的创建正是为了处理这类事情
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
文件说:
try with resources语句确保关闭每个资源
在陈述的结尾
在这里依赖终结器是一个非常糟糕的举动。只有在对流对象进行垃圾收集时,才会调用终结器,并且您很可能在垃圾收集之前很久就用完了文件句柄。永远不要依赖终结器实现功能。我再怎么强调也不为过。根本无法保证终结器是否会运行。我知道依赖终结器的危险。我的观点很简单,获取IOExceptions不是一个正常的流程,对于这种不寻常的情况,可能不值得在关闭文件描述符时挂起太多的电话。您上次在一个文件输入流中看到多个IOVORATION是什么时候?
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}