在Java中关闭输入流

我在try / catch块中有以下代码段

InputStream inputstream = conn.getInputStream(); InputStreamReader inputstreamreader = new InputStreamReader(inputstream); BufferedReader bufferedreader = new BufferedReader(inputstreamreader); 

我的问题是,当我必须在finally块中关闭这些流时,是否必须关闭所有3个流,或者只是关闭befferedreader将关闭所有其他流?

按照惯例,封装流(包装现有流)在关闭时关闭底层流,因此只需关闭示例中的bufferedreader 。 此外,关闭已经关闭的流通常是无害的,因此关闭所有3个流不会受到伤害。

通常可以关闭最外层的流,因为按照惯例,它必须在底层流上触发关闭。

所以通常代码看起来像这样:

 BufferedReader in = null; try { in = new BufferedReader(new InputStreamReader(conn.getInputStream())); ... in.close(); // when you care about Exception-Handling in case when closing fails } finally { IOUtils.closeQuietly(in); // ensure closing; Apache Commons IO } 

然而,在极少数情况下,基础流构造函数会引发流已经打开的exception。 在这种情况下,上面的代码不会关闭底层流,因为外部构造函数从未被调用,并且in为null。 所以finally块不会关闭任何东西,而是打开底层流。

从Java 7开始,您可以这样做:

  try (OutputStream out1 = new ...; OutputStream out2 = new ...) { ... out1.close(); //if you want Exceptions-Handling; otherwise skip this out2.close(); //if you want Exceptions-Handling; otherwise skip this } // out1 and out2 are auto-closed when leaving this block 

在大多数情况下,您不希望在关闭时引发exception处理,因此请跳过这些显式的close()调用。

编辑这里是非信徒的一些代码,使用这种模式是非常重要的。 您可能还想阅读关于closeQuietly()方法的Apache Commons IOUtils javadoc。

  OutputStream out1 = null; OutputStream out2 = null; try { out1 = new ...; out2 = new ...; ... out1.close(); // can be skipped if we do not care about exception-handling while closing out2.close(); // can be skipped if we ... } finally { /* * I've some custom methods in my projects overloading these * closeQuietly() methods with a 2nd param taking a logger instance, * because usually I do not want to react on Exceptions during close * but want to see it in the logs when it happened. */ IOUtils.closeQuietly(out1); IOUtils.closeQuietly(out2); } 

当创建out2引发exception时,使用out2的“建议”将会打开out1 。 这个建议来自某人It's a continual source of errors for obvious reasons. 好吧,我可能会失明,但这对我来说并不明显。 我的模式在我可以想到的每个用例中都是白痴安全的,而Tom的模式容易出错。

关闭最外面的一个就足够了(即BufferedReader )。 阅读BufferedReader的源代码,我们可以看到它在调用自己的close方法时关闭内部Reader

 513 public void close() throws IOException { 514 synchronized (lock) { 515 if (in == null) 516 return; 517 in.close(); 518 in = null; 519 cb = null; 520 } 521 } 522 } 

根据经验,您应该按照打开它们的相反顺序关闭所有内容。

我会按照你打开它们的相反顺序关闭它们,好像打开它们时会将读取器推到一个堆栈中,关闭会使读取器从堆栈中弹出。

最后,在关闭所有内容后,“阅读器堆栈”必须为空。

您只需要关闭实际资源。 即使构造装饰器失败,您也应该关闭资源。 对于输出,您应该在快乐的情况下刷新最装饰器对象。

一些并发症:

  • 有时装饰器是不同的资源(一些压缩实现使用C堆)。
  • 在悲伤情况下关闭装饰器实际上会导致刷新,随之而来的混乱,例如实际上没有关闭底层资源。
  • 看起来您的底层资源是URLConnection ,它没有disconnect / close方法。

您可能希望考虑使用Execute Around习语,这样您就不必复制此类内容。