【问题标题】:Java: can't get stdout data from Process unless its manually flushedJava:除非手动刷新,否则无法从 Process 获取标准输出数据
【发布时间】:2011-05-12 23:07:57
【问题描述】:

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

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);
}

只有在我立即刷新 both 两端的输出时才有效。也就是说,我必须刷新每个用户输入,并且子进程必须刷新自己的 stdout 才能使事情发生。否则,read() 阻塞,等待数据,这些数据从未真正发送(子进程的标准输出只是保持缓冲)。如何让 I/O 运行?

示例终端子进程:

#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 上运行。

【问题讨论】:

    标签: java process io buffer


    【解决方案1】:

    在将数据写入磁盘之前,您无法从文件中读取数据。 在数据被放入管道/套接字的缓冲区之前,您无法从套接字或管道中读取数据。

    您的 java 程序无法控制 (*) 外部进程何时刷新其输出并将数据写入磁盘/管道缓冲区/套接字缓冲区。您完全受制于外部程序的缓冲行为。在每种操作系统和每种编程语言中都是如此。

    每个网络程序员都必须处理这个问题,所以就处理它吧。

    (*) - 有时某些程序(例如 cat 之一)有选项 (-u) 来指示程序使用无缓冲输出。否则你是仁慈的

    【讨论】:

    • 对,但是对于我的 Java 程序,I/O 从不 被发送,而如果我在终端中手动运行所述子进程,I/O 几乎是即时的。跨度>
    • 是的,我们知道我们必须处理它。问题是如何。
    【解决方案2】:

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

    但这并不总是可行的,尤其是在处理第三方代码时。在这种情况下,我所知道的最好的 other 修复方法是使用像 Expect 这样的工具来欺骗子进程。在内部,Expect 知道如何伪装成终端(在 Unix 上使用 ptys,在 Windows 上使用可怕的 hack)来欺骗其他程序关闭(或至少减少)它们的缓冲。有一个用于 Expect 的脚本 - unbuffer - 使其专门专注于这种用途。 (总的来说,它可以做的不仅仅是处理不规则的缓冲,但无论如何它是最好的解决方法。)

    【讨论】:

      【解决方案3】:

      您没有从事件调度线程运行您的 I/O 读取循环吗?

      您应该在单独的线程中运行从子进程读取的 I/O(如果您还没有这样做的话)。每个 GUI 按键立即刷新到子进程可能是最好的;除非你想支持某种“一次读一整行”的东西。

      【讨论】:

      • 这就是我目前正在做的事情。我有一个从子进程读取的单独线程(因为read() 块),它通知主线程中的事件处理程序。击键立即发送到子进程并刷新。
      猜你喜欢
      • 2011-01-08
      • 2020-06-22
      • 2015-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      • 2011-01-12
      相关资源
      最近更新 更多