正确关闭Java进程的getInputStream()返回的输入流

42

我在文档中没有找到这个问题的明确解释。 但是当我们有一个Process对象并调用getInputStream()时,

我们是否得到一个新的流,当我们完成后应该明确关闭它? 还是 我们得到已经与进程相关联的流,我们不应该关闭它,但进程会负责关闭它?

基本上,我们应该如何与从Process.getInputStream()获得的流进行交互?关闭还是不关闭?

5个回答

14

从阅读UNIXProcess.java代码来看,以下是发生的情况:

我们需要区分两种状态:进程仍在运行,或者它已经死亡。

如果进程仍在运行,通过关闭输出流(流向进程的标准输入),您正在告诉进程没有更多的输入。通过关闭输入流(进程的标准输出和标准错误),进程将不能再向这些流写入数据(如果尝试写入数据,则会收到SIGPIPE信号)。

当进程终止时,Java将缓冲剩余的stdout / stderr数据,并为您关闭所有三个流(它正在运行“进程收割者”线程,该线程在进程死亡时被通知)。任何试图写入OutputStream的尝试都将失败。如果有缓冲的数据,从InputStream读取将返回这些数据。关闭其中任何一个流没有好处,也不会造成任何损失。(底层文件描述符此时已关闭)。


你能备份一下吗?这是一个有趣的主题,你的回答很详细。谢谢。 - FranXho
关闭InputStream是否一定清除缓冲区?即,如果进程已停止但缓冲区中有未读数据,关闭InputStream是否一定会从缓冲区中删除这些数据? - Edd

11

我的第一反应是关闭它,因为你打开的流总是要关闭的。我确实意识到文档不够完善,但既然它们没有明确说明不要关闭,那对我来说就意味着要遵循良好的编程实践。

InputStream is = process.getInputStream()
try {
    // your code
} finally {
    try { is.close(); } catch (Exception ignore) {}
}

如果您需要确保这没有问题,只需编写一个快速的测试用例,在该测试用例中从输入流中多次读取数据,每次打开和关闭InputStream即可。


5
IOUtils.closeQuietly(is) 将会处理 try { is.close(); } catch(Exception ignore) {} 的操作。其作用是关闭输入流is,如果在关闭时出现异常,也会被忽略掉。 - Kirby

8
当你调用Process.getInputStream()时,你会得到一个已经为该进程设置好的现有输入流。当进程结束时,该输入流不会自动消失 - 把它想象成一个你仍然可以读取的缓冲区。管道的进程端可能关闭了,但你的端口没有。虽然垃圾回收最终会处理它,但关闭它是你的责任。
你还应该关闭另外两个: getErrorStream()getOutputStream()

3
当进程终止时,该输入流不会自动消失。当您启动一个进程时,Java会运行“进程回收器”线程,在这种情况下关闭此类管道的本地侧。 - Peter Štibraný

1

如果您没有打开流,则不要关闭它们-这是一个令人讨厌的副作用。如果您创建了该进程,请先终止它,然后再关闭流。


-1

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