在 java 中读取进程的实时输出

Read live output of process in java

我在 java 应用程序中使用

启动了一个 python 脚本
Process p = Runtime.getRuntime().exec("python script.py");

此脚本循环运行,仅由事件(或用户交互)取消。该脚本在每个循环周期写入输出,一些文本如“12:22:35 -- Heartbeat”

while True:
  print("Heartbeat")
  time.sleep(1)

在我的 Java 应用程序中,我想读取显示的输出。我的问题是,如果我使用 BufferReader,它将等到进程完成,然后读取输出。以下是我的阅读方式:

BufferedReader is = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;

while ((line = is.readLine()) != null)
   System.out.println(line);

如何读取输出 "live"?

为了更好地理解:python-脚本侦听硬件按钮,按下此按钮时,会写出一些输出。在我的 java 应用程序中,我想显示此消息并将其发送给一些客户。

我经常写这样的东西:

class StreamHandler extends Thread {

    InputStream is;
    Writer writer;

    StreamHandler(InputStream is, Writer writer) {
        super("StreamHandler");

        this.is = is;
        this.writer = writer;
    }

    @Override
    public void run() {
        try (InputStreamReader isr = new InputStreamReader(is)) {

            char buffer[] = new char[256];
            int n;
            while ((n = isr.read(buffer)) > 0) {
                writer.write(buffer, 0, n);
            }
        } catch (IOException e) {
            System.err.println("StreamHandler: " + e);
        }
    }
}

虽然我使用它来将输出流捕获到我自己的缓冲区,但您可以简单地实时回显 stdout,例如:

Process process = Runtime.getRuntime().exec(...);
Writer writer = new OutputStreamWriter(System.out);
StreamHandler stdout_handler = new StreamHandler(process.getInputStream(), writer);
stdout_handler.start();

使用https://github.com/zeroturnaround/zt-exec

new ProcessExecutor().command("python", "script.py")
    .redirectOutput(new LogOutputStream() {
        @Override
        protected void processLine(String line) {
            ...
        }
    })
    .execute();

尝试将您的 python 代码更改为:

while True:
    print("Heartbeat", flush=True)
    time.sleep(1)

我一直在尝试和你做同样的事情,并找到了这个问题的解决方案:PumpStreamHandler can capture the process output in realtime

如果你只想打印到当前进程的流,那么你可以使用ProcessBuilder class创建一个进程并让它“继承”IO流像这样:

Process process = new ProcessBuilder()
            .command(commandList)
            .directory(workingDirectory)
            .inheritIO()
            .start();

或者,如果您想更好地控制流,

Process process = new ProcessBuilder()
            .command(commandList)
            .directory(workingDirectory)
            .redirectOutput(ProcessBuilder.Redirect.INHERIT)
            .redirectInput(ProcessBuilder.Redirect.INHERIT)
            .redirectError(ProcessBuilder.Redirect.INHERIT)
            .start();

同样,这可能适用于您的情况,也可能不适用,这取决于程序所在的终端 运行。我已经在系统终端中使用 java 程序尝试了 运行 mysqlpython 命令行解释器,它工作正常。

但是如果你想将输出重定向到其他地方,那么来自进程的标准输出将被缓冲(参见 here)。在您的情况下,缓冲区仅在程序完成期间被刷新。因此,在 print 中设置 flush=True 就像答案中提到的@Mateus Terra 可能会起作用。