Java exec - 交互式进程的输出一直保留到进程终止为止

标签 java process 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!

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

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

最佳答案

遗憾的是,这不是一个错误,而是一个功能。无论是在Linux上还是在Windows上管道都是这样实现的。它们被缓冲以提高性能。第一个进程生成数据,第二个进程接管数据。无需交互,该模型在 99% 的情况下都有效。

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

该进程不会自动刷新输出。无论进程是用哪种语言编写的。用 Java、Perl 或 C 编写的进程在显式刷新添加到其代码之前永远不会打印提示。如果您可以影响将与之交互的进程的代码,请更新代码(伪代码如下):

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

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

提示:查看 Apache Commons Exec 。它是一个专门用于流程执行的库。

关于Java exec - 交互式进程的输出一直保留到进程终止为止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10546122/

相关文章:

java - 从设备读取数据?

java - 通过 Google App Engine 的 Google Drive API

java - Activity <Activity name> 已泄漏最初在此处添加的窗口 DecorView@59feb10[activity]

c# - 取消长时间操作的最佳方法是什么?

Linux、waitpid、WNOHANG、子进程、僵尸

bash - shell脚本,for循环,does循环等待执行命令进行迭代

java - 任何用于 Java 应用程序开发的 RAD 工具?

java - 使用自动滚动将处理输出流式传输到 Javafx Textarea

c - 如何通过调用 exec 函数族的成员来获取程序运行的返回值?

PHP - 在客户端断开连接时杀死 exec