为什么InputStreamReader不能实时读取进程的输出?

时间:2013-01-22 10:38:44

标签: java process io inputstream

我正在尝试使用ProcessBuilder来运行一些外部命令,例如Linux中的ifstatvmstat

此类命令支持自定义采样间隔。如果我向外部命令添加一个采样间隔,例如ifstat 20,那么命令将输出如下:

coolcfan@coolcfan-PC:~$ ifstat 20
       eth0               wlan0               vmnet1              vmnet8      
 KB/s in  KB/s out   KB/s in  KB/s out   KB/s in  KB/s out   KB/s in  KB/s out

20秒后

   41.29      1.06      0.36      0.00      0.00      0.00      0.00      0.00
再过20秒

   16.67      0.58      0.38      0.00      0.00      0.00      0.00      0.00

然而,当我使用我的Java代码运行命令时,输出的第一部分将在20秒后读取,如下所示:

Start running "ifstat 20"

20秒后

       eth0               wlan0               vmnet1              vmnet8      
 KB/s in  KB/s out   KB/s in  KB/s out   KB/s in  KB/s out   KB/s in  KB/s out
   66.61      1.73      1.29      0.01      0.00      0.00      0.00      0.00

当我使用NIO服务器运行命令并使用SocketChannel将输出发送到客户端时,问题更加严重......(我的客户端需要再等待20秒才能从服务器获取服务器的输出显示过程开始后20秒的第一个输出

我注意到输出延迟的长度与我为命令设置的间隔有关。

那么为什么ISR不能实时读取输出?

一个简单的测试代码片段来演示我的问题:

public static void main(String[] args) {
    ProcessBuilder pb = new ProcessBuilder();

    pb.command("ifstat 20".trim().split(" "));

    Process p = null;

    System.out.println("Start running \"ifstat 20\"");

    try {
        p = pb.start();

        char[] buf = new char[512];

        InputStreamReader isr = new InputStreamReader(p.getInputStream());

        int count = -1;

        while ((count = isr.read(buf, 0, buf.length)) != -1) {
            System.out.print(new String(buf, 0, count));
        }
    }
    catch (IOException ioe) {
    }
}

更新

正如彼得的评论,这不是与Java相关的问题。这是一个管道延迟

但我仍然不明白,为什么vmstat 20 | cat没有这种延迟,而ifstat 20 | cat会延迟显示头部?

1 个答案:

答案 0 :(得分:2)

确实如此。

该进程的输出被延迟。 STDIO做缓冲,根据粗壮或不是终端而变化。