读取其他进程'**无缓冲**输出流

时间:2013-02-19 17:15:44

标签: java process stream stdout unbuffered

我正在为java中的文件转换器编写一个小GUI。文件转换器将其当前进度写入stdout。看起来像这样:

Flow_1.wav: 28% complete, ratio=0,447

我想在进度条中说明这一点,所以我正在阅读这个过程'stdout:

ProcessBuilder builder = new ProcessBuilder("...");
builder.redirectErrorStream(true);
Process proc = builder.start();
InputStream stream = proc.getInputStream();
byte[] b = new byte[32];
int length;
while (true) {
    length = stream.read(b);
    if (length < 0) break;
    // processing data
}

现在的问题是,无论选择哪个字节数组大小,都会以4 KB的块读取流。所以我的代码一直执行到length = stream.read(b);,然后阻塞了很长一段时间。一旦进程生成4 KB输出数据,我的程序就会得到这个块并以32字节的片段完成它。然后再等待下一个4 KB。

我试图强制java使用这样的小缓冲区:

BufferedInputStream stream = new BufferedInputStream(proc.getInputStream(), 32);

或者这个:

BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()), 32);

但两项都没有改变。

然后我发现了这个:Process source(第87行)

似乎Process类的实现方式是将进程'stdout传递给文件。那么proc.getInputStream();实际上做的是将流返回到文件。此文件似乎是用4 KB缓冲区写的。

有没有人知道这种情况的某种解决方法?我只想立即获得流程输出。

EDIT :正如Ian Roberts所建议的那样,我也试图将转换器的输出传输到stderr流中,因为这个流似乎不包含在BufferedInputStream中。还是4k块。

另一件有趣的事情是:我实际上并没有获得4096字节,而是大约5字节。我担心FileInputStream本身是本地缓冲的。

1 个答案:

答案 0 :(得分:2)

查看链接到流程标准输出流的代码将包含在BufferedInputStream中,但其标准错误仍未缓冲。因此,一种可能性可能是直接执行转换器,而是执行一个shell脚本(或Windows等效,如果你在Windows上)将转换器的stdout发送到stderr:

ProcessBuilder builder = new ProcessBuilder("/bin/sh", "-c",
  "exec /path/to/converter args 1>&2");

不要 redirectErrorStream,然后从proc.getErrorStream()而不是proc.getInputStream()阅读。

可能是您的转换器已经使用stderr进行进度报告,在这种情况下您不需要脚本位,只需关闭redirectErrorStream()即可。如果转换器程序写入stdout和stderr,那么你将需要产生第二个线程来使用stdout(脚本方法通过将所有内容发送到stderr来解决这个问题)。