【问题标题】:How to reliably read and write to a running external process from Java?如何可靠地从 Java 读取和写入正在运行的外部进程?
【发布时间】:2012-10-31 14:46:54
【问题描述】:

我希望能够从 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

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

【问题讨论】:

  • 如果有帮助,请在此处查看我的答案,stackoverflow.com/questions/13008526/…
  • 谢谢,阿勒姆。我没有考虑到 stdErr 可能会填满并且消除同步问题是一个不错的方法。但是,在单独的线程中从 stdErr 读取在这里没有帮助。我希望能够将数据推送到进程,让进程工作——例如处理线路或等待任何响应,然后再继续,就像从 shell 运行一样。我应该用 bash -c "..." 结束我的外部进程吗?
  • 我没有尝试过在java中运行unix进程但是windows进程,你必须尝试一下。但据我了解,您希望自己而不是系统控制应用程序的退出。为此,您始终可以将 proc.destroy() 放在自定义条件中..??
  • os.close() 和 proc.destroy() 都可以。我的问题是通过进程的输出推送输出内容,如果可用,可以在调用close()或destroy()之前读取。 (bash -c 失败了。)link 对类似问题有否定的结论。同样对于通用进程,外部进程完成输入处理后未定义它,因此使用 Arham 的线程建议可能会产生更清洁的解决方案。
  • 别忘了从链接中为我的回答点赞!! :)

标签: java io external-process


【解决方案1】:

一般来说,所采取的方法是正确的。不过有几件事:

  1. InputStream.read() 是一种阻塞方法。它等待输入并且不是 CPU 密集型的。你应该围绕它转...
  2. 可以读取多个字节,只要使用read(byte[] buffer, int offset, int len)
  3. 将输入流包装到 BufferedInputStream 可以简化访问(readLine() 方法)。这是 BufferedReader 的替代方案。
  4. 别忘了使用Process.waitFor()

另外,确保外部进程写入标准输出(而不是标准错误)。这里有两种可能性:

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

【讨论】:

  • 谢谢,user999441。 Process.waitFor() 阻塞,直到外部进程完成。我想在终止之前保持进程运行并从其输出中读取。
  • 在您杀死它之前,该过程不会完成,无论是通过字面杀死,还是通过发送 EOF (Ctrl + D)。或者 Ctrl + C。此外,以文件作为输入和输出运行进程可能是一个更好的主意 - 进程在文件中输入,执行作业,将其写入文件,完成,然后 Java 处理输出文件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-02
  • 1970-01-01
  • 1970-01-01
  • 2019-02-11
  • 2020-05-13
  • 2017-04-13
相关资源
最近更新 更多