同时从外部进程消耗stdout

时间:2009-06-22 16:12:17

标签: java

是否有一种线程安全的方法可以使用Java 1.6中的ProcessBuilder从外部进程并发使用stdout?

背景:我需要调用pbzip2将大文件解压缩到stdout并在文件解压缩时处理每一行(pbzip2使用多个CPU,与其他实现不同)。

逻辑方法是创建一个子线程来遍历InputStream(即stdout;你不喜欢命名吗?),如下所示:

while((line = reader.readLine()) != null)
{
     // do stuff
}

然而,解压缩很慢,所以我真正需要的是reader.readLine方法静静地等待下一行可用,而不是退出。

有没有好办法呢?

3 个答案:

答案 0 :(得分:2)

您应该可以使用InputStreamReaderBufferedReader来包装输入流。然后,您可以调用readLine(),然后根据需要阻止。

请注意,您应该有一个相应的stderr阅读器。您不必对它执行任何操作,但是您需要使用stderr流,否则您生成的进程可能会阻塞。有关链接等,请参阅this answer

答案 1 :(得分:1)

您自己或多或少都有解决方案。您只需创建一个新线程,该线程从外部进程流中读取循环中的下一行并处理该行。

readLine()将阻塞并等待整个新行可用。如果您使用的是多核/处理器计算机,则在您的线程处理线路时,您的外部进程可以愉快地继续解压缩。 Atleast解压缩可以继续,直到OS管道/缓冲区变满。

请注意,如果您的处理速度低于解压缩,则会阻止解压缩,此时它会成为内存与速度问题。例如你可以创建一个除了读取行之外什么都不做的线程(因此解压缩不会阻塞),将它们缓存在内存中的队列中,另一个线程 - 甚至是几个消耗所述队列的线程。

  

readLine方法静静等待   下一行可用,   而不是退出

这正是readLine应该做的,它只会阻塞直到整行可用。

答案 2 :(得分:1)

我已经编写了一些代码,它们在一个Process(由流程构建器生成)中启动了一个耗时的工作(ffmpeg),然后它启动了我的OutputStreamReader类,它是一个消耗线程的Thread的扩展。 stdio并用它做了一些魔术。

catch(对我而言)是重定向错误流。这是我的代码片段:

        procbbuilder.redirectErrorStream(true);
        proc = pb.start();
        err = new MyOutputStreamReader(this, proc.getInputStream());  //extenion of thread
        err.start();

        int exitCode = proc.waitFor();