Java 为什么InputStreamReader不';t读取过程';实时输出?

Java 为什么InputStreamReader不';t读取过程';实时输出?,java,process,io,inputstream,Java,Process,Io,Inputstream,我正在尝试使用ProcessBuilder运行一些外部命令,如Linux中的ifstat或vmstat 此类命令支持自定义采样间隔。如果我将采样间隔添加到外部命令中,例如,ifstat 20,则该命令的输出如下: coolcfan@coolcfan-PC:~$ ifstat 20 eth0 wlan0 vmnet1 vmnet8 KB/s in KB/s out KB/s in

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

此类命令支持自定义采样间隔。如果我将采样间隔添加到外部命令中,例如,
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
Start running "ifstat 20"
20秒后

   41.29      1.06      0.36      0.00      0.00      0.00      0.00      0.00
   16.67      0.58      0.38      0.00      0.00      0.00      0.00      0.00
       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
再过20秒

   41.29      1.06      0.36      0.00      0.00      0.00      0.00      0.00
   16.67      0.58      0.38      0.00      0.00      0.00      0.00      0.00
       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
但是当我使用Java代码运行命令时,输出的第一部分将在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
Start running "ifstat 20"
20秒后

   41.29      1.06      0.36      0.00      0.00      0.00      0.00      0.00
   16.67      0.58      0.38      0.00      0.00      0.00      0.00      0.00
       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) {
    }
}

更新:

正如Peter所说,这与Java无关。这是管道延迟

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

它有


延迟的是进程的输出。STDIO进行缓冲,缓冲根据stout是否为终端而变化。

ISR读取您得到的任何内容。为了进行比较,运行ifstat 20 | cat,这样它就可以写入管道而不是控制台了。@PeterLawrey,这是管道问题吗?实际上,我需要在真实环境中运行
ifstat 120
。数据似乎没有延迟,只有标题。@PeterLawrey好的,好的,是的。。但是为什么头部延迟显示?我怀疑它没有明显的发红。写入控制台时会自动刷新,但写入管道时需要显式刷新,直到第一行数据出现时才会进行刷新。@coolcfan fflush()在C程序中。您无法从外部执行任何操作。唯一可以执行的操作是下载ifstat的源代码,在写入标头后添加一个fflush(),然后改用该版本。应该注意的是,某些程序检测到tty,并且在写入tty时比其他目的地(例如文件或管道)进行的缓冲更少。您可以创建一个伪tty来减少缓冲,即使输出不会发送到终端。@EJP+1对于“C程序中的fflush()”,这是我寻找了8个小时的解决方案,终于开始工作了。还想知道它为什么起作用吗?这有什么诀窍?