Java exec - 交互过程的输出一直持续到进程终止 [英] Java exec - output of interactive process is held till process has terminated

查看:182
本文介绍了Java exec - 交互过程的输出一直持续到进程终止的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a problem with an interactive process in Java. I have threads to read STDOUT and STDERR and a thread to handle input for the process. But there are no data available within the STDOUT stream until the process has terminated. Then is the entire output printed at once.

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程序写入的行作为调试信息。让我们尝试在系统控制台中执行相同的过程。

The lines prefixed with STDOUT are lines written by the process. The lines prefixed with STDIN are lines written by me. Lines prefixed by DBG are lines written by the tested Java program as debug information. Let's try to execute the same process in system console.

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

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

The behavior fullfits my expectation. I'm asked for some input. I do it and get the answer.

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

I'm surprissed, that I've found several posts on web including Stackoverflow, but without any answer marked as acceptable solution. (For example Problem reading InputStream from Java Process.) It seems Java developers haven't ever been dealing with execution of an interactive process. Strange is, that output of non-interactive process (as ping) is appearing sequentially, while the process is running. Without any problem. But when the process is waiting for user input, the output is somehow blocked.

推荐答案

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

Regrettably it is not a bug, it is a feature. Either on Linux or on Windows pipes are implemented like this. They are buffered in order to increase performace. One process produces data and the second one takes them over. There is no interaction needed and this model works in 99% cases as well.

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

However the console is another kind of application. The system console is a part of OS and it works a bit other way the our console written in Java. The system console of course prints all data immediately. All works fine. Then the same process executed from our code does not print prompts, albeit it shall work. What's wrong? There is no buffer between system console and process. But there is a buffer between our process and our Java code on the contrary. And that's the cause.

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

The process does not flush output automatically. Regardless to the language the process is written in. Process written in Java, Perl or C never prints prompts until explicit flush has been added to its code. If you can affect the code of a process you will interact with, update the code (pseudocode follows):

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

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

There is not another solution. If the third-party application does not flush its outputs, you cannot use it in your console. You can hardly evade the buffering. Nevertheless it is possible somehow. There are libraries or you can find an open source application which can interact with problematic processes and inspect its code.

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

Tip: Check out Apache Commons Exec. It is a library specialized in process executing.

这篇关于Java exec - 交互过程的输出一直持续到进程终止的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆