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

14

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

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

从类中复制的描述:Reader

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

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

更新:

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

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

InputStreamReader 的实现将close调用直接传递给本地类StreamDecoder


4
是的。你认为除了哪个流之外,“the stream”指的是哪个流? - Andy Turner
1
@KlitosKyriacou InputStreamReader 会关闭StreamDecoder,而StreamDecoder会关闭与其链接的InputStream。请参考源代码 - AxelH
@AxelH和AndyTurner,你们俩都是对的。我已经搞混了。 - Klitos Kyriacou
1
@KlitosKyriacou 这取决于你所说的“close”的含义。我的意思是,InputStreamReader.close()会调用InputStreamclose()方法;而这个方法所做的事情对于InputStreamReader来说相当不相关。 - Andy Turner
2
有趣的是,相比之下,java.util.Scanner的Javadoc更加清晰明确:“当Scanner被关闭时,如果源实现了Closeable接口,则会关闭其输入源。” 另一方面,InputStreamReader.close()的Javadoc只是从Reader.close()接口复制而来。还有其他的Readers。StringReader.close()的Javadoc也说:“关闭流并释放与其关联的任何系统资源。” 这是针对一个字符串上的Reader。它所说的这个流是什么? - Klitos Kyriacou
显示剩余2条评论
2个回答

10

正如其他答案和评论所说,答案是肯定的,它确实关闭了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.

0
这取决于流的实现。就 close() 而言,InputStream 只是一个“接口”。InputStreamReader 不会关闭接口,而是会关闭底层数据资源(如文件描述符),如果有的话。如果在实现中覆盖并清空了 close,它将不执行任何操作。
在 OpenJdk 中,StreamDecoder 有一个方法。
void implClose() throws IOException {
    if(this.ch != null) {
        this.ch.close();
    } else {
        this.in.close();
    }
}

this.in 是解码器构造函数中的输入流:

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只是一个接口。”我希望这是真的。但事实并非如此。 - Sean Patrick Floyd
你能证明你的陈述吗?不幸的是,官方文档含糊不清,而实现部分又涉及到本地代码,这使得检查变得很困难... - gavenkoa
4
InputStreamReader.close() 会在 InputStream 上调用 close 方法。如果 InputStream 忽略了这个调用,那么这并不关 InputStreamReader 的事。 - Andy Turner
@AndyTurner 你是凭借自己的经验说的还是有证据支持你的陈述? - gavenkoa
@gavenkoa 在源代码中查看 - Andy Turner
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接