2

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

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

我想在进度条中说明这一点,所以我正在阅读流程的标准输出,如下所示:

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 (about line 87)

似乎 Process 类的实现方式是将进程的标准输出通过管道传输到文件。那么proc.getInputStream();实际上所做的是将流返回到文件。而且这个文件似乎是用 4 KB 缓冲区写入的。

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

编辑:正如 Ian Roberts 所建议的,我还尝试将转换器的输出通过管道传输到 stderr 流中,因为该流似乎没有包装在BufferedInputStream. 仍然是 4k 块。

另一个有趣的事情是:我实际上并没有得到 4096 个字节,而是大约 5 个字节。恐怕它FileInputStream本身是本机缓冲的。

4

1 回答 1

2

查看链接到进程标准输出流的代码被包装在 a 中,BufferedInputStream但它的标准错误仍然没有缓冲。因此,一种可能性可能是不直接执行转换器,而是将转换器的标准输出发送到标准错误的 shell 脚本(或 Windows 等效脚本,如果您在 Windows 上):

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 来解决这个问题)。

于 2013-02-19T17:37:32.833 回答