32

在伪代码中,这就是我正在做的事情:

Process proc = runtime.exec(command);
processOutputStreamInThread(proc.getInputStream());
processOutputStreamInThread(proc.getErrorStream());
proc.waitFor()

但是,有时processOutputStreamInThread看不到任何输出,有时会看到。粗略地说,该方法创建BufferedInputStream命令的输出并将其发送到记录器。

根据我所看到的,我猜测command不需要将所有输出转储到由getInputStream()and馈送的流getErrorStream()中,从而允许流为空。

我的试验结果是以下问题:

(1) java.lang.ProcesswaitFor()中是否要求执行程序的输出在返回之前已被读取?

该文档仅说明:

如有必要,使当前线程等待,直到此Process对象表示的进程终止。如果子进程已经终止,则此方法立即返回。如果子进程尚未终止,则调用线程将被阻塞,直到子进程退出。

(2)在什么条件下,由提供的流需要关闭和/或自动关闭getInputStreamgetErrorStream

该文档仅说明:

获取子流程的错误流。该流从该 Process 对象表示的进程的错误输出流中获取通过管道传输的数据。

实施说明:缓冲输入流是个好主意。

一位用户报告说他必须自己关闭流,但至少在部分时间我得到一个异常,表明当我尝试这样做时流已经关闭。

编辑:更改getOutputStreamgetInputStream,现在出现在上面。

解决方案:问题最终是在某些情况下,用于处理输出流的线程直到我的非常短暂的进程完成后才会运行,导致输入流没有给我任何数据。 waitFor没有做任何等待执行程序的输出。相反,程序在收集任何输出之前运行并终止。

我使用线程是因为我不确定我将在标准错误和标准输出上获得多少输出,并且我希望能够同时处理这两者,而不会阻塞其中一个或另一个应该只有其中一个有可用数据。但是,因为我的线程不能一致地读取执行程序的输出,所以这是一个非解决方案。

我的最终编码看起来像这样:

ProcessBuilder pb = new ProcessBuilder(cmdargs);
pb.redirectErrorStream(true);
Process proc = pb.start();
processOutputStream(proc.getInputStream());
proc.waitFor()
4

2 回答 2

29

如果您的外部进程期望它的某些东西stdin,您必须关闭getOutputStream. 否则你会waitFor永远。

这是来自 JavaWorld 的When Runtime.exec() won't 文章,它描述了 exec 方法的不同陷阱以及如何避免它们。

根据我的经验,最好消耗子进程的 STDOUT 和 STDERR (直到它们 EOF )然后阻止waitFor。希望此时您不必等待很长时间。

对 Kaleb 问题的回答。在正常情况下,您不应该关闭流,但是因为您是waitingFor并且无论出于何种原因它都没有超时,如果您在输出中遇到一些错误情况并且不想处理子流,则可能需要关闭这些流进一步输出。但是,子程序是否会在其 STDOUT 或 STDERR 管道在另一端关闭时终止(崩溃)完全取决于该子程序的实现。但是,大多数 shell 程序都会在这种情况下终止。

我真的希望waitFor有一些有意义的超时,并且Process当你决定放弃它的监控时,有一个记录在案的方法来清理它的资源。

于 2010-01-27T23:33:34.000 回答
2

我认为这有点违反直觉,但是:

getOutputStream 获取子进程的输出流。流的输出通过管道传输到此 Process 对象表示的进程的标准输入流中。实施说明:缓冲输出流是个好主意。返回:连接到子进程正常输入的输出流。

我将其作为主进程的输出流读取并附加到子进程的标准输入,因此当您写入 getOutputStream().write() 时,您实际上是在标准输入上写入。

你可能想使用 .getInputStream() 吗?

返回:连接到子进程正常输出的输入流。

至于 Process.Waitfor() API 文档说:

如有必要,使当前线程等待,直到此 Process 对象表示的进程终止。如果子进程已经终止,则此方法立即返回。如果子进程尚未终止,则调用线程将被阻塞,直到子进程退出。

我会说这个被调用的线程将被阻塞,直到进程完成执行 - 您可能仍在此阶段处理输出,具体取决于其他线程,或者它们可能在您的线程返回之前完成。

于 2010-01-27T22:41:30.720 回答