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

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

问题描述

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

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()块,等待数据,这是从未实际发送的(子进程'stdout只是保持缓冲)。如何进行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\n", c);
        // doesn't work in my Java program if the next line isn't present
        fflush(stdout);
    }
    return 0;
}

我正在使用Sun Java 6在Ubuntu 10.10上运行。

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知道如何假装成一个终端(在Unix上使用ptys和在Windows上使用神秘黑客),因此欺骗其他程序关闭(或至少减少)他们的缓冲。 Expect有一个脚本 - unbuffer - 专门针对这种用途。 (一般来说,它可以做的不仅仅是处理不守规矩的缓冲,但无论如何它都是最好的修复。)

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获取stdout数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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