Java 当标准输出流可用时,从子流程读取标准输出流

Java 当标准输出流可用时,从子流程读取标准输出流,java,stream,subprocess,apache-commons-exec,Java,Stream,Subprocess,Apache Commons Exec,在我的Java应用程序中,我需要执行一些脚本作为子进程,并监视来自Java的标准输出,以便在必要时对某些输出作出反应 我正在使用ApacheCommonsExec生成子进程,并将已执行脚本的stdout重定向到输入流 我遇到的问题是,当从流中读取时,Java进程被阻塞,直到子进程完成执行。我不能等到子流程结束时才对输出做出反应,但我需要在输出可用时异步读取它 下面是我的Java代码: public class SubProcessReact { public static class L

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

我正在使用ApacheCommonsExec生成子进程,并将已执行脚本的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();

谢谢你的回答,但这并不能解决我的问题。我需要能够阅读每一行,因为它进入流。使用此解决方案,我遇到了与原始代码中相同的问题,我只能在脚本完成执行后才能获得整个结果。我需要能够一次读取java代码中的每一行。@Aptrick:此外,为了在java代码中一次读取一行,您可能需要
-u
标志来禁用
python
的stdout/stderr流的缓冲。否则,重定向时输出将被块缓冲。看@J.F.Sebastian这解决了我的问题。我认为问题不在Python方面。非常感谢@阿帕特里克:不客气。顺便说一句,如果将流重定向到管道/文件,则使其完全缓冲对于基于C stdio的程序来说是常见的,这不是特定于Python的,例如,这就是为什么
grep
具有
--line buffered
选项的原因。合理的做法是,如果没有用户查看输出,那么块缓冲模式可以提高性能。看见