【问题标题】:Does closing an InputStreamReader also close the underlying InputStream?关闭 InputStreamReader 是否也会关闭底层 InputStream?
【发布时间】:2017-06-21 10:20:52
【问题描述】:

InputStreamReader 的 JavaDoc 没有说明关闭底层 InputStream

https://docs.oracle.com/javase/8/docs/api/java/io/InputStreamReader.html#close--

从班级复制的描述:读者

关闭流并释放与其关联的所有系统资源。关闭流后,进一步的 read()、ready()、mark()、reset() 或 skip() 调用将引发 IOException。关闭之前关闭的流没有任何效果。

关闭 InputStreamReader 是否也会关闭底层 InputStream?

更新在:

InputStreamReader istream = new InputStreamReader(conn.getInputStream(), "UTF-8")
istream.close();

我需要关闭conn.getInputStream()吗?

InputStreamReader 实现直接 close 调用 StreamDecoder 这是一个原生类。

【问题讨论】:

  • 是的。您认为“流”指的是哪个流?
  • @AndyTurner 我想你会发现它没有关闭它。
  • @KlitosKyriacou InputStreamReader 将关闭 StreamDecoder 以关闭指向它的 InputStream 链接。见the source code
  • @KlitosKyriacou 这取决于您所说的“关闭”是什么意思。我的意思是InputStreamReader.close() 调用了InputStreamclose() 方法;这与InputStreamReader 完全无关。
  • 作为一个兴趣点,相比之下,java.util.Scanner 的 Javadoc 似乎更清晰、更明确:“当 Scanner 关闭时,如果源实现 Closeable 接口。”另一方面,InputStreamReader.close() 的Javadoc 只是接口Reader.close() 的一个副本。还有其他读者。 StringReader.close() 的 Javadoc 还说“关闭流并释放与之关联的任何系统资源”。这适用于字符串上的阅读器。它在说什么流?

标签: java


【解决方案1】:

正如其他答案和 cmets 所说,答案是肯定的,它确实关闭了 InputStream。你可以用下面的代码自己看看:

    InputStream is = new FileInputStream("D:\\a.txt");
    Reader r = new InputStreamReader(is);
    r.close();
    is.read();  // throws exception: stream is closed.

因此,如果您关闭 Reader,则无需同时关闭 InputStream。但是,我猜你到处都在使用 try-with-resources(不是吗?;))并且 InputStream 以及 Reader 都将在 try 块的末尾关闭。没关系,因为 InputStream 可以多次关闭;如果流已经关闭,则为空操作。

如果你想避免关闭 InputStream,你可以编写一个简单的包装器,它在关闭时什么都不做:

    class UncloseableInputStream extends FilterInputStream {
        public UncloseableInputStream(InputStream is) {
            super(is);
        }
        public void close() {
            // Do nothing.
        }
    }

    InputStream is = new FileInputStream("D:\\a.txt");
    Reader r = new InputStreamReader(new UncloseableInputStream(is));
    r.close();
    is.read();  // still works despite closing the reader.

【讨论】:

    【解决方案2】:

    这取决于流的实现。 InputStream 只是 close() 的一个“接口”。 InputStreamReader 不会关闭界面。如果是,它将关闭底层数据资源(如文件描述符)。如果 close 在实现中被覆盖并为空,它将什么也不做。

    在OpenJdk中StreamDecoder有一个方法

    void implClose() throws IOException {
        if(this.ch != null) {
            this.ch.close();
        } else {
            this.in.close();
        }
    }
    

    this.in 是来自解码器构造函数的 InputStream:

    StreamDecoder(InputStream var1, Object var2, CharsetDecoder var3) {
        ...
        if(this.ch == null) {
            this.in = var1;
            ...
        }
        ...
    }
    

    以下是关闭操作的示例。 ByteArrayInputStream:

    关闭 ByteArrayInputStream 无效。该类中的方法可以在流关闭后调用,不会产生 IOException。

    public void close() throws IOException {
    }
    

    FileInputStream 不同:

    关闭此文件输入流并释放与该流关联的所有系统资源。如果此流具有关联的通道,则该通道也将关闭。关闭底层实例后,无论哪个接口使用它都无关紧要,它将被关闭。

    public void close() throws IOException {
        synchronized (closeLock) {
            if (closed) {
                return;
            }
            closed = true;
        }
        if (channel != null) {
           channel.close();
        }
    
        fd.closeAll(new Closeable() {
            public void close() throws IOException {
               close0();
           }
        });
    }
    

    【讨论】:

    • "InputStream 只是一个接口。"我希望那是真的。不是。
    • 你能证明你的说法吗?不幸的是,官方文档模棱两可,并且实施到了使检查难以完成的本机代码......
    • InputStreamReader.close()InputStream 上调用close。如果InputStream 忽略该调用,则与InputStreamReader 无关。
    • @SeanPatrickFloyd 它是close 的术语,它只是一个“接口”。究竟会发生什么取决于实施。
    • @AndyTurner 你是根据自己的经验说的还是有证据证明你的说法?
    猜你喜欢
    • 2010-11-28
    • 2014-08-13
    • 2015-11-17
    • 2023-03-06
    • 2010-11-14
    • 2012-12-12
    • 2012-03-23
    • 2010-12-18
    • 2019-01-20
    相关资源
    最近更新 更多