2

在我的 Java 应用程序中,我需要将一些脚本作为子进程执行并监视 Java 标准输出上的输出,以便在必要时对某些输出做出反应。

我正在使用 apache commons-exec 生成子进程并将执行脚本的标准输出重定向到输入流。

我遇到的问题是,从流中读取时,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 脚本,它在输出之间有 1 秒的延迟,向上计数,以便我可以验证 Java 代码在数据进入时是否响应。

蟒蛇代码:

import time

for x in range(0,10):
    print x
    time.sleep(1)

我希望 LogOutputStreamImpl 打印每一行,但实际发生的是它读取流块直到子进程完成,然后打印所有输出。

我可以做些什么来按我的意愿完成这项工作吗?

4

1 回答 1

1

为什么要使用第三方库来做 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();
于 2015-12-20T17:10:58.247 回答