如何从Java可靠地读取和写入正在运行的外部进程?

时间:2012-10-31 14:46:54

标签: java io external-process

我希望能够从Java生成外部进程,并定期写入其输入并读取响应,就好像它是控制台一样。但是,在我阅读流程输出时,大部分时间都没有。有没有做好这种事情的好习惯(甚至避免它)?

以下是一个不起作用的简要示例:

import org.apache.commons.exec.*;
import java.io.*;
//...
CommandLine cl = CommandLine.parse("/usr/bin/awk {print($1-1)}");
System.out.println(cl.toStrings());
Process proc = new ProcessBuilder(cl.toStrings()).start();
OutputStream os = proc.getOutputStream(); // avoiding *Buffered* classes
InputStream is = proc.getInputStream();   // to lessen buffering complications
os.write(("4" + System.getProperty("line.separator")).getBytes());
os.flush(); // Doesn't seem to flush.
// os.close(); // uncommenting works, but I'd like to keep the process running
System.out.println("reading");
System.out.println(is.read()); // read even one byte? usually is.available() -> 0

奇怪的是,如果我在BufferedWriter中包装OutputStream,我可以从一些进程(cat)读取,但不能读取其他进程(awk,grep)。

1 个答案:

答案 0 :(得分:1)

通常,采取的方法是正确的。但事情很少:

  1. InputStream.read()是一种阻止方法。它等待输入并且不是CPU密集型的。你应该围绕它......
  2. 可以读取多个字节,只需使用read(byte[] buffer, int offset, int len)
  3. 将输入流包装到BufferedInputStream可以简化访问(readLine()方法)。这是BufferedReader的替代方案。
  4. 不要忘记使用Process.waitFor()
  5. 此外,请确保外部进程写入标准输出(而不是标准错误)。这里有两种可能性:

    1. 使用Process.getErrorStream()(并将其视为另一个InputStream)
    2. 将命令行更改为/usr/bin/awk {print($1-1)} 2>&1。这会将标准错误重定向到标准输出。