关闭 Java FileInputStream
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/156508/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Closing a Java FileInputStream
提问by Matt H
Alright, I have been doing the following (variable names have been changed):
好的,我一直在做以下事情(变量名称已更改):
FileInputStream fis = null;
try
{
fis = new FileInputStream(file);
... process ...
}
catch (IOException e)
{
... handle error ...
}
finally
{
if (fis != null)
fis.close();
}
Recently, I started using FindBugs, which suggests that I am not properly closing streams. I decide to see if there's anything that can be done with a finally{} block, and then I see, oh yeah, close() can throw IOException. What are people supposed to do here? The Java libraries throw too many checked exceptions.
最近,我开始使用 FindBugs,这表明我没有正确关闭流。我决定看看是否有任何可以用 finally{} 块完成的事情,然后我看到,哦,是的,close() 可以抛出 IOException。人们应该在这里做什么?Java 库抛出太多已检查的异常。
采纳答案by McDowell
For Java 7 and above try-with-resourcesshould be used:
对于 Java 7 及更高版本,应使用try-with-resources:
try (InputStream in = new FileInputStream(file)) {
// TODO: work
} catch (IOException e) {
// TODO: handle error
}
If you're stuck on Java 6 or below...
如果您一直使用 Java 6 或更低版本...
This pattern avoids mucking around with null:
这种模式避免了null:
try {
InputStream in = new FileInputStream(file);
try {
// TODO: work
} finally {
in.close();
}
} catch (IOException e) {
// TODO: error handling
}
For a more detail on how to effectively deal with close, read this blog post: Java: how not to make a mess of stream handling. It has more sample code, more depth and covers the pitfalls of wrapping closein a catchblock.
有关如何有效处理close的更多详细信息,请阅读此博客文章:Java:如何不弄乱流处理。它有更多的示例代码、更深入的内容并涵盖了在catch块中关闭包装的陷阱。
回答by Max Stewart
Something like the following should do it, up to you whether you throw or swallow the IOException on attempting to close the stream.
像下面这样的事情应该做到这一点,取决于您是否在尝试关闭流时抛出或吞下 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)
{
}
}
回答by squiddle
You could also use a simple static Helper Method:
您还可以使用简单的静态 Helper 方法:
public static void closeQuietly(InputStream s) {
if (null == s) {
return;
}
try {
s.close();
} catch (IOException ioe) {
//ignore exception
}
}
and use this from your finally block.
并从您的 finally 块中使用它。
回答by Lars Westergren
Hopefully we will get closures in Java some day, and then we will lose lots of the verbosity.
希望有一天我们会在 Java 中使用闭包,然后我们将失去很多冗长的内容。
So instead there will be a helper method somwhere in javaIO that you can import, it will probably takes a "Closable" interface and also a block. Inside that helper method the try {closable.close() } catch (IOException ex){ //blah} is defined once and for all, and then you will be able to write
因此,您可以在 javaIO 中的某个位置导入一个辅助方法,它可能需要一个“Closable”接口和一个块。在该辅助方法中, try {closable.close() } catch (IOException ex){ //blah} 一劳永逸地定义,然后您将能够编写
Inputstream s = ....;
withClosable(s) {
//your code here
}
回答by serg10
Nothing much to add, except for a very minor stylistic suggestion. The canonical example of self documenting codeapplies in this case - give a descriptive variable name to the ignored IOException
that you must catch on close()
.
除了一个非常小的风格建议外,没有什么可添加的。 自记录代码的规范示例适用于这种情况 - 为IOException
您必须抓住的被忽略的提供一个描述性变量名称close()
。
So squiddle's answer becomes:
所以squiddle的答案变成了:
public static void closeQuietly(InputStream s) {
try {
s.close();
} catch (IOException ignored) {
}
}
回答by Dave Griffiths
Are you concerned primarily with getting a clean report from FindBugs or with having code that works? These are not necessarily the same thing. Your original code is fine (although I would get rid of the redundant if (fis != null)
check since an OutOfMemoryException
would have been thrown otherwise). FileInputStream has a finalizer method which will close the stream for you in the unlikely event that you actually receive an IOException in your processing. It's simply not worth the bother of making your code more sophisticated to avoid the extremely unlikely scenario of
您主要关心从 FindBugs 获得干净的报告还是拥有有效的代码?这些不一定是一回事。你的原始代码很好(虽然我会去掉多余的if (fis != null)
检查,因为OutOfMemoryException
否则会被抛出)。FileInputStream 有一个终结器方法,它会在您在处理中实际收到 IOException 的不太可能的事件中为您关闭流。为了避免极不可能的情况,让您的代码更加复杂根本不值得
- you get an IOException and
- this happens so often that you start to run into finalizer backlog issues.
- 你得到一个 IOException 和
- 这种情况经常发生,以至于您开始遇到终结器积压问题。
Edit:if you are getting so many IOExceptions that you are running into problems with the finalizer queue then you have far far bigger fish to fry! This is about getting a sense of perspective.
编辑:如果您收到如此多的 IOExceptions 以至于您遇到了终结器队列的问题,那么您将有更大的鱼要煎!这是关于获得透视感。
回答by Bruno De Fraine
In most cases, I find it is just better notto catch the IO exceptions, and simply use try-finally:
在大多数情况下,我发现最好不要捕获 IO 异常,而只需使用 try-finally:
final InputStream is = ... // (assuming some construction that can't return null)
try {
// process is
...
} finally {
is.close();
}
Except for FileNotFoundException
, you generally can't "work around" an IOException
. The only thing left to do is report an error, and you will typically handle that further up the call stack, so I find it better to propagate the exception.
除了FileNotFoundException
,您通常无法“解决” IOException
. 剩下要做的唯一事情就是报告一个错误,您通常会在调用堆栈上进一步处理它,所以我发现传播异常更好。
Since IOException
is a checked exception, you will have to declare that this code (and any of its clients) throws IOException
. That might be too noisy, or you might not want to reveal the implementation detail of using IO. In that case, you can wrap the entire block with an exception handler that wraps the IOException
in a RuntimeException
or an abstract exception type.
由于IOException
是受检异常,您必须声明此代码(及其任何客户端)throws IOException
。这可能太吵了,或者您可能不想透露使用 IO 的实现细节。在这种情况下,您可以使用一个异常处理程序来包装整个块,该异常处理程序将 包装IOException
在 aRuntimeException
或抽象异常类型中。
Detail:I am aware that the above code swallows any exception from the try
block when the close
operation in the finally
block produces an IOException
. I don't think that is a big problem: generally, the exception from the try
block will be the same IOException
that causes the close
to fail (i.e. it is quite rare for IO to work fine and then fail at the point of closing). If this is a concern, it might be worth the trouble to "silence" the close.
详细信息:我知道try
当块中的close
操作finally
产生一个IOException
. 我不认为这是一个大问题:通常,try
块的异常与IOException
导致close
失败的异常相同(即 IO 正常工作然后在关闭时失败是非常罕见的)。如果这是一个问题,那么“沉默”关闭可能是值得的。
回答by Olivier Cailloux
The following solution correctly throws an exception if close fails without hiding a possible exception before the close.
如果关闭失败,以下解决方案会正确抛出异常,而没有在关闭之前隐藏可能的异常。
try {
InputStream in = new FileInputStream(file);
try {
// work
in.close();
} finally {
Closeables.closeQuietly(in);
}
} catch(IOException exc) {
// kernel panic
}
This works because calling close a second time has no effect.
这是有效的,因为第二次调用 close没有效果。
This relies on guava Closeables, but one can write its own closeQuietly method if preferred, as shown by squiddle(see also serg10).
这依赖于番石榴Closeables,但如果愿意,可以编写自己的 closeQuietly 方法,如squiddle所示(另见serg10)。
Reporting a close error, in the general case, is important because close might write some final bytes to the stream, e.g. because of buffering. Hence, your user wants to know if it failed, or you probably want to act somehow. Granted, this might not be true in the specific case of a FileInputStream, I don't know (but for reasons already mentioned I think it is better to report a close error if it occurs anyway).
在一般情况下,报告关闭错误很重要,因为关闭可能会将一些最终字节写入流,例如由于缓冲。因此,您的用户想知道它是否失败,或者您可能想以某种方式采取行动。当然,在 FileInputStream 的特定情况下,这可能不是真的,我不知道(但由于已经提到的原因,我认为如果无论如何发生错误,最好报告关闭错误)。
The above code is a bit difficult to grasp because of the structure of the embedded try blocks. It might be considered clearer with two methods, one that throws an IOException and one that catches it. At least that is what I would opt for.
由于嵌入的 try 块的结构,上面的代码有点难以掌握。使用两种方法可能会更清楚,一种抛出 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
}
}
Based on http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html(referenced by McDowell).
基于http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html(由 McDowell 引用)。
回答by Edwin Dalorzo
You could use the try-with-resourcesfeature added JDK7. It was created precisely to deal with this kind of things
您可以使用JDK7 中添加的try-with-resources功能。正是为了处理这种事情而创建的
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
The documenation says:
文档说:
The try-with-resources statement ensures that each resource is closed at the end of the statement.
try-with-resources 语句确保每个资源在语句结束时关闭。