Java exec – 交互过程的输出一直持续到进程终止

我在Java中使用交互式进程时遇到问题。 我有线程来读取STDOUT和STDERR以及一个处理进程输入的线程。 但是,在流程终止之前,STDOUT流中没有可用的数据。 然后立即打印整个输出。

DBG | Pipe action-STDERR started DBG | Pipe action-STDIN started DBG | Pipe action-STDOUT started STDIN | Try to put some input. STDIN | I cannot see any output. STDIN | Nevertheless the interaction works. STDIN | It works on background. STDIN | Let's terminate the process to see the truth. STDIN | quit STDOUT | Enter some text, please: The text is 'Try to put some input.' STDOUT | Enter some text, please: The text is 'I cannot see any output.' STDOUT | Enter some text, please: The text is 'Nevertheless the' STDOUT | Enter some text, please: The text is 'interaction works.' STDOUT | Enter some text, please: The text is 'It works on background.' STDOUT | Enter some text, please: The text is 'Let's terminate the process to see the truth.' STDOUT | Enter some text, please: The text is 'quit' STDOUT | Bye! DBG | Trying to kill thread action-STDOUT DBG | Trying to kill thread action-STDERR DBG | Trying to kill thread action-STDIN DBG | Pipe action-STDERR finished DBG | Finished DBG | Pipe action-STDIN finished DBG | Pipe action-STDOUT finished 

以STDOUT为前缀的行是由该过程写入的行。 以STDIN为前缀的行是由我写的行。 以DBG为前缀的行是由测试的Java程序写入的行作为调试信息。 让我们尝试在系统控制台中执行相同的过程。

 Enter some text, please: Text The text is 'Text' Enter some text, please: quit The text is 'quit' Bye! 

这种行为符合我的期望。 我被要求提供一些意见。 我这样做并得到答案。

我很惊讶,我在网上发现了几个post,包括Stackoverflow,但没有任何答案被标记为可接受的解决方案。 (例如, 从Java Process读取InputStream的问题 。)似乎Java开发人员从未处理过交互式进程的执行。 奇怪的是,当进程正在运行时,非交互式进程(如ping)的输出顺序出现。 没有任何问题。 但是当进程等待用户输入时,输出会以某种方式被阻止。

遗憾的是,这不是一个错误,它是一个function。 无论是在Linux上还是在Windows上,管道都是这样实现的。 它们被缓冲以提高性能。 一个过程产生数据,第二个过程接管它们。 不需要交互,此模型也适用于99%的情况。

然而,控制台是另一种应用程序。 系统控制台是操作系统的一部分,它的工作方式与我们用Java编写的控制台不同。 系统控制台当然会立即打印所有数据。 一切正常。 然后从我们的代码执行相同的过程不会打印提示,虽然它应该工作。 怎么了? 系统控制台和进程之间没有缓冲区。 但是,相反,我们的进程和Java代码之间存在缓冲。 这就是原因。

该过程不会自动刷新输出。 无论编写进程的语言如何。用Java,Perl或C编写的进程从不打印提示,直到将明确的flush添加到其代码中。 如果您可以影响要与之交互的进程的代码,请更新代码(伪代码如下):

 print 'Give me a number ' flush STDOUT number = get STDIN print 'You wrote ' + number flush STDOUT 

没有其他解决方案。 如果第三方应用程序未刷新其输出,则无法在控制台中使用它。 你几乎无法逃避缓冲。 尽管如此,它有可能。 有库或您可以找到一个开源应用程序,它可以与有问题的进程交互并检查其代码。

提示:查看Apache Commons Exec 。 它是一个专门处理流程的库。