在我的Java应用程序中,我需要将一些脚本作为子流程来执行,并监控来自Java的stdout上的输出,以便在必要时对某些输出做出反应。
我使用apachecommons-exec生成子进程,并将已执行脚本的stdout重定向到输入流。
我遇到的问题是,当从流中读取时,Java进程会被阻塞,直到子进程完成执行。我不能等到子流程结束才对输出做出反应,但我需要在它可用时异步读取它。
下面是我的Java代码:
public class SubProcessReact {
public static class LogOutputStreamImpl extends LogOutputStream {
@Override
protected void processLine(String line, int logLevel) {
System.out.println("R: " + line);
}
}
public static void main (String[] args) throws IOException, InterruptedException {
CommandLine cl = CommandLine.parse("python printNumbers.py");
DefaultExecutor e = new DefaultExecutor();
ExecuteStreamHandler sh = new PumpStreamHandler(new LogOutputStreamImpl());
e.setStreamHandler(sh);
Thread th = new Thread(() -> {
try {
e.execute(cl);
} catch (IOException e1) {
e1.printStackTrace();
}
});
th.start();
}
}
在这个例子中,子流程是一个python脚本,它在输出之间有一秒的延迟向上计数,这样我就可以验证Java代码在数据进入时是否有响应
Python代码:
import time
for x in range(0,10):
print x
time.sleep(1)
我希望LogOutputStreamImpl在每一行出现时都打印它,但实际发生的是,它读取流块,直到子流程完成,然后打印所有输出。
我能做些什么让这件事按我的意愿进行吗?
为什么要使用第三方库来做Java SE已经做得很好的事情?就我个人而言,我更喜欢依赖尽可能少的外部库,以便使我的程序易于移植并减少故障点:
ProcessBuilder builder = new ProcessBuilder("python", "printNumbers.py");
builder.inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE);
Process process = builder.start();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
reader.lines().forEach(line -> System.out.println("R: " + line));
}
process.waitFor();