读取文件以处理Stdin ProcessBuilder

时间:2015-08-25 19:07:43

标签: java

如何使用ProcessBuilder将文件传递到进程的stdin?我正在读取流的程序是用C语言编写的,但我对此一无所知。

以下是相关的java:

  ProcessBuilder pb = new ProcessBuilder("./program").inheritIO();
  Process p = pb.start();
  DataInputStream din = new DataInputStream(new FileInputStream("./my-file.txt"));
  byte[] dinBytes = new byte[din.available()];
  din.readFully(dinBytes);
  din.close();
  OutputStream os = p.getOutputStream();
  os.write(dinBytes);
  os.close();
  int rc = p.waitFor();
  System.out.println("RC: " + rc);

返回以下错误:

java.io.IOException: Stream closed
    at java.lang.ProcessBuilder$NullOutputStream.write(ProcessBuilder.java:434)
    at java.io.OutputStream.write(OutputStream.java:116)
    at java.io.OutputStream.write(OutputStream.java:75)
    at Test.main(Test.java:14)
$ input in flex scanner failed

1 个答案:

答案 0 :(得分:4)

您的错误原因是您在构建流程时调用.inheritIO()。这会导致所有进程的标准文件描述符从Java进程继承。 documentation说:

  

这是一种方便的方法。调用表单

pb.inheritIO()
     

的行为方式与调用

完全相同
pb.redirectInput(Redirect.INHERIT)   
  .redirectOutput(Redirect.INHERIT)
  .redirectError(Redirect.INHERIT)

redirectInput(Redirect)的文档说:

  

如果源是Redirect.PIPE(初始值),则可以使用Process.getOutputStream()返回的输出流写入子进程的标准输入。如果源设置为任何其他值,则Process.getOutputStream()将返回空输出流。

因此,基本上,默认情况是Java进程和构建进程之间存在管道,以便您可以将数据从程序推送到进程。但是你从管道中释放了进程的标准输入并让它等待来自用户控制台的输入,但是你试图将它视为它仍然是管道的一部分,然后得到管道的末端以便推送里面的数据。你得到一个空输出流,一旦你尝试在其中加入一些东西,你就会得到一个例外。

所以你不应该打那个电话。而且由于您需要来自文本文件的输入,最简单的方法实际上是将该输入流直接重定向到该文件。同样,重定向会破坏管道 - 但您不需要它,因为重定向实际上可以满足您的需求:

// Take input from a file, output and error go to user console
pb = new ProcessBuilder("./program")
         .redirectInput(new File("./my-file.txt"))
         .redirectOutput(Redirect.INHERIT)
         .redirectError(Redirect.INHERIT);
Process p = pb.start();
int rc = p.waitFor();

如果要管道多个文件,另一种方法是将管道保持为流程标准输入,但使用Files复制文件:

pb = new ProcessBuilder("./program")
         .redirectOutput(Redirect.INHERIT)
         .redirectError(Redirect.INHERIT);
Process p = pb.start();
OutputStream os = p.getOutputStream();
Files.copy( Paths.get("./my-file-1.txt"), os );
Files.copy( Paths.get("./my-file-2.txt"), os );
// more files

os.close();
int rc = p.waitFor();

关于DataInputStream:它是用于处理从InputStream写入的二进制数据的DataOutputStream类型 - 以二进制形式写入的int,double等。当然,像任何InputStream一样,您可以按原样从中读取字节。但为此,你真的不需要将它包装在DataInputStream中。