在Java中关闭输入流

时间:2012-06-29 14:45:25

标签: java inputstream

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

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

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

6 个答案:

答案 0 :(得分:27)

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

答案 1 :(得分:5)

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

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

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
}

然而,在极少数情况下,基础流构造函数会引发流已经打开的异常。在这种情况下,上面的代码不会关闭底层流,因为外部构造函数从未被调用,in为空。所以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

在大多数情况下,您不希望在关闭时引发异常处理,因此请跳过这些显式的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);
    }

out1的创建引发异常时,使用@ Tom的“建议”会打开out2。这个建议来自某人谈论It's a continual source of errors for obvious reasons.嗯,我可能是盲人,但这对我来说并不明显。在Tom的模式容易出错的情况下,我能想到的每个用例都是我的模式。

答案 2 :(得分:3)

关闭最外面的一个就足够了(即BufferedReader)。阅读source code of 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   }

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

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

一些并发症:

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

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