应该显式关闭BufferedReader和InputStreamReader吗?

3
我想把一个InputStream的内容读入一个String中:
private String readToString(InputStream stream) {
    return new BufferedReader(new InputStreamReader(stream))
            .lines().collect(Collectors.joining("\n"));
}

这个流来自于java.lang.Process

问题:在这种情况下,我是否需要明确关闭InputStreamInputStreamReaderBufferedReader中的任何一个?

附注:链接的问题不是重复的,因为我的问题是关于如何正确关闭流,而不是如何将流读取为字符串!


3
不要关闭任何东西。如果你关闭 BufferedReader 或 InputStreamReader,它们会隐式地关闭 InputStream。但是这个责任应该由打开它的人承担(最好在 try-with-resources 中)。此外,如果您想将整个文本读入 String,不要逐行读取再将这些行重新连接成一个字符串。换行符没有必要意味着文件必须这样拆分。而是以字节的形式读取整个文件,然后使用所选的编码将其转换为字符。 - DodgyCodeException
2
@KlitosKyriacou 那个问题是2008年的,已经过去了将近10年。 - Eugene
@Eugene,尽管有新的东西被引入,但它仍然有效。仅仅因为新事物被引入并不意味着它们比现有的更好。此外,OP只想将文件读入单个字符串中,所以没有必要先将其拆分成行,使用适当的分隔符的Scanner会很好地完成工作。 - DodgyCodeException
1
@DodgyCodeException 实际上,即使问题旧了,那里的一些答案仍然很新!其中一个答案使用了Java 9的功能。 - Klitos Kyriacou
2
我刚看到你的编辑,并理解了这个问题不是重复的。我已经撤回了我的关闭投票。 - Klitos Kyriacou
显示剩余3条评论
2个回答

6
您只需要关闭 outer 包装器,但无论如何都不要显式地这样做 - 有一个 try-with-resource 可以让您的生活更轻松:
public String readToString(InputStream stream) {

    try (InputStreamReader reader = new InputStreamReader(stream);
            BufferedReader br = new BufferedReader(reader)) {

        return br.lines().collect(Collectors.joining("\n"));

    } catch (IOException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}

还有一种更加简单明了的方法:

Files.readAllLines(YourPath)

1
我正在从java.lang.process获取输入流,因此无法使用Files。但是可以使用try-with。 - membersound

3
根据我的评论,关闭BufferedReader或InputStreamReader将导致InputStream被关闭。您的readToString方法不应关闭流。这是调用者的责任。
原因如下:
首先,在调用readToString之前,请考虑如何打开流。一个明智的方法是:
try (InputStream myStream = getInputStreamSomehow()) {
    //...
    String content = readToString(myStream);
    //...
}

在try-with-resources块结束时,流将被关闭。

其次,考虑现有的最佳实践和习惯用法。查看与您的方法一样读取流的整个内容的Java API方法。例如,从Java 9开始:

上述两种方法都不会关闭流。同样地,您的readToString方法的用户也不会期望您关闭他们的流。


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