即使InputStream保持打开状态,我是否需要关闭InputStreamReader?

3

InputStream 作为参数从某处传递进来,将在那里被进一步处理,然后关闭。因此我不想在这里关闭 InputStream。考虑以下代码:

void readInputStream(final InputStream inputStream) {
    final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    String line;
    while ((line = bufferedReader.readLine() != null) {
        // do my thing
    }
}

如果我关闭BufferedReader和/或InputStreamReader,那么根据另一个Stackoverflow帖子的说法,底层的InputStream也将被关闭。
我的问题是:即使底层的InputStream在其他地方已经关闭,读取器是否仍需要关闭?如果不关闭读取器,会导致内存泄漏吗?

我不完全理解你的问题,但通常来说,像这样的资源在使用完毕后应该关闭。此外,我建议您查看try-with-resources,它将自动为您关闭它们。最后,您的代码片段并不是针对这个问题最合适的。 - akortex
你的方法可能不应该创建自己的 BufferedReader,而是将其作为参数传入。这样,你的应用程序中将只有 一个 BufferedReader,并且当它不再需要时可以关闭它,这也会关闭底层的 InputStream - Pshemo
@Pshemo InputStream被传递到不同的处理程序中,每个处理程序都会对其进行不同的操作。每次在使用之前都会重置它(并在最后关闭)。只有这个处理程序实际上需要一个BufferedReader,另一个处理程序只是将InputStream传递给库函数等等。 - entreprenr
2个回答

4
读者需要关闭吗,即使底层的InputStream在其他地方已经关闭了?
在这种情况下,他们绝对不需要。但通常最好还是将它们关闭。
不关闭读取器会导致内存泄漏吗?
不会,假设您在完成使用后不再需要Reader本身。并且此外,Reader通常不会使用大量内存。
更重要的问题是,如果不关闭Reader,是否会出现资源泄漏。答案是...这取决于具体情况。
如果您可以保证底层的InputStream将始终在应用程序的其他地方被关闭,则会处理可能的内存泄漏。
如果不能保证,则存在资源泄漏的风险。在Linux中,底层的操作系统级文件描述符是有限资源。如果JVM不关闭它们,则它们可能用尽,并且某些系统调用将开始意外失败。
但是,如果您关闭了Reader,则底层的InputStream将会关闭。
InputStream上多次调用close()是无害的,并且几乎不会花费任何代价。
唯一不应该关闭Reader的情况是在关闭底层的InputStream是错误的情况下。例如,如果关闭SocketInputStream,则其余应用程序可能无法重新建立网络连接。同样,与System.in相关联的InputStream通常无法重新打开。
在这种情况下,允许您在方法中创建的Reader进行垃圾回收实际上是安全的。与InputStream不同,典型的Reader类不会覆盖Object :: finalize()以关闭其数据源。
如果您正在接受InputStream作为参数,则使用本地Reader(特别是BufferedReader)包装它可能是错误的设计。 BufferedReader可能会预读流。如果此方法返回后调用者将继续使用流,则缓冲区中已读取但未被此方法使用的任何数据可能会丢失。
更好的做法是调用者传递一个 Reader。或者,应该将此方法记录为“拥有”InputStream。在这种情况下,它应该始终关闭它。

我的使用情况是用户可以上传文件,这个文件可以被许多不同的处理程序解释。因此,第一个处理程序尝试以特定格式读取文件,如果不是该格式,则下一个处理程序将读取文件,依此类推。每当新的处理程序读取它时,输入流都会被重置。这就是为什么它被传递的原因。但是你的答案证实了我所想的,谢谢 :) - entreprenr

1

是的,读者需要关闭。使用代理,例如 CloseShieldInputStream,防止传递的参数被关闭。

void readInputStream(InputStream inputStream) throws IOException{

  try (var bufferedReader = new BufferedReader(new InputStreamReader(
       new CloseShieldInputStream(inputStream)))) {

    String line;
    while ((line = bufferedReader.readLine()) != null) {
      // do my thing
    }
  }
}

JIC:与输入屏蔽器类似,Apache Commons I/O还提供了一个输出屏蔽器来解决关闭包装输出流的类似问题,- CloseShieldOutputStream


如需更详细的考虑,请参考原始答案。感谢 @stephen-c


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