Java:除非手动刷新,否则无法从 Process 获取标准输出数据 [英] Java: can't get stdout data from Process unless its manually flushed

查看:46
本文介绍了Java:除非手动刷新,否则无法从 Process 获取标准输出数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用 Java 为命令行程序编写终端包装器,并使用 ProcessBuilder 生成子进程.要将击键发送到子进程,我只需将 e.getKeyChar() 从 GUI 直接写入 proc.getOutputStream() 给出的 OutputStream.为了从子进程接收输出,我基本上有一个从子进程的 stdout 读取的 while 循环:

I'm writing a terminal wrapper for a command-line program in Java, and I spawn the subprocess using ProcessBuilder. To send keystrokes to the subprocess, I just write e.getKeyChar() from the GUI straight to the OutputStream given by proc.getOutputStream(). To receive output from the subprocess, I basically have a while loop that reads from the subprocess's stdout:

while ((b = br.read()) != -1) {
    System.out.println("Read "+b);
    bb[0] = (byte) b;
    // call an event listener with the read byte
    listener.dataReceived(bb);
}

这有效,如果我立即刷新两端的输出.也就是说,我必须刷新每个用户输入,并且子进程必须刷新它自己的 stdout 以便事情发生.否则, read() 阻塞,等待数据,这些数据实际上从未发送过(子进程的标准输出只是保持缓冲).我如何才能进行 I/O?

This works, only if I immediately flush the output on both ends. That is, I have to flush every user input and the subprocess has to flush its own stdout in order for stuff to happen. Otherwise, read() blocks, waiting for data, which is never actually sent (subprocess' stdout just keeps buffering). How can I get I/O going?

示例终端子进程:

#include <stdio.h>

int main() {
    char c;
    while((c = getchar()) != -1) {
        printf("Got: %d
", c);
        // doesn't work in my Java program if the next line isn't present
        fflush(stdout);
    }
    return 0;
}

我在 Ubuntu 10.10 和 Sun Java 6 上运行.

I'm running on Ubuntu 10.10 with Sun Java 6.

推荐答案

许多运行时库(例如,我知道 libc 会这样做,如果其他人也这样做,我也不会感到惊讶)默认情况下会缓冲它们的输出除非输出到终端.这在处理多行(例如,在正常管道中)时极大地提高了数据处理的效率,但是当只有少量信息时,它会受到很大伤害.如果您可以访问子进程的源代码,那么最好通过关闭缓冲或添加刷新来更新代码.

Many many runtime libraries (e.g., I know that libc does this, and wouldn't be at all surprised if others do too) will buffer their output by default except when the output is to a terminal. This enormously increases the efficiency of data handling when dealing with many lines (e.g., in a normal pipeline) but when there is only a small amount of information, it hurts a lot. If you have access to the source of the subprocess, it's definitely best to update the code by turning off buffering or adding flushes.

但这并不总是可行的,尤其是在处理第三方代码时.在这种情况下,我所知道的最好的其他解决方法是使用像 Expect 欺骗子进程.在内部,Expect 知道如何伪装成一个终端(在 Unix 上使用 ptys,在 Windows 上使用令人毛骨悚然的 hacks),从而诱使其他程序关闭(或至少减少)它们的缓冲.有一个脚本 - unbuffer - 对于 Expect 来说,它特别专注于这种使用.(一般来说,它可以做的不仅仅是处理不守规矩的缓冲,但无论如何它都是最好的解决办法.)

But that's not always possible, especially when dealing with third-party code. The best other fix I know of in that case is to use a tool like Expect to trick the subprocess. Internally, Expect knows how to pretend to be a terminal (using ptys on Unix and godawful hacks on Windows) so tricking the other programs into turning off (or at least reducing) their buffering. There is a script – unbuffer – for Expect that makes it focus specifically on this sort of use. (In general it can do a lot more than just dealing with unruly buffering, but it's the best fix anyway.)

这篇关于Java:除非手动刷新,否则无法从 Process 获取标准输出数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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