使用Java从外部程序中重定向stdin和stdout运行程序

5

我正在尝试从Java程序中运行一个外部程序,但遇到了困难。基本上我想做的是:

 Runtime.getRuntime().exec("./extprogram <fileIn >fileOut");

然而,我发现这并不起作用 - Java显然需要使用带有输入和输出流以及其他我不熟悉的东西的Process。我查看了互联网上的许多示例(其中许多来自SO),似乎没有简单标准的方法来完成这个任务,对于那些不完全理解正在发生的事情的人来说,这可能非常令人沮丧。此外,我试图根据其他人代码的示例构建自己的代码时遇到了麻烦,因为通常大多数人 1. 不感兴趣重定向stdin,2. 不一定将stdout重定向到文件,而是重定向到System.out。所以,是否有人能够指引我朝着调用外部程序并重定向stdinstdout的良好简单代码模板的方向?谢谢。
3个回答

9
您可以尝试这样做:

您可以尝试类似以下的方法:

ProcessBuilder pb = new ProcessBuilder();
pb.redirectInput(new FileInputStream(new File(infile));
pb.redirectOutput(new FileOutputStream(new File(outfile));
pb.command(cmd);
pb.start().waitFor();

2
1+ 但不要忘记错误流,可以通过调用 bp.redirectErrorStream(true) 将其折叠到进程的 InputStream 中。 - Hovercraft Full Of Eels
ProcessBuilder 没有 redirectInput()redirectOutput() 函数。http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ProcessBuilder.html - MattS
@MattS\s\1.5.0\7 http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html - corsiKa
我会在工作中与系统管理员谈一下,也许他们会让我升级。 - MattS
我认为这不起作用,没有一个名为ProcessBuilder.redirectOutput()的方法可以接受一个OutputStream - Nico
显示剩余2条评论

7
如果你必须使用Process,那么以下代码应该可以工作:
public static void pipeStream(InputStream input, OutputStream output)
   throws IOException
{
   byte buffer[] = new byte[1024];
   int numRead = 0;

   do
   {
      numRead = input.read(buffer);
      output.write(buffer, 0, numRead);
   } while (input.available() > 0);

   output.flush();
}

public static void main(String[] argv)
{
   FileInputStream fileIn = null;
   FileOutputStream fileOut = null;

   OutputStream procIn = null;
   InputStream procOut = null;

   try
   {
      fileIn = new FileInputStream("test.txt");
      fileOut = new FileOutputStream("testOut.txt");

      Process process = Runtime.getRuntime().exec ("/bin/cat");
      procIn = process.getOutputStream();
      procOut = process.getInputStream();

      pipeStream(fileIn, procIn);
      pipeStream(procOut, fileOut);
   }
   catch (IOException ioe)
   {
      System.out.println(ioe);
   }
}

注意:
  • 确保关闭流。
  • 将其更改为使用缓冲流,我认为原始的Input/OutputStreams实现可能会逐字节复制。
  • 进程的处理可能会根据您的特定进程而变化:cat是使用管道I/O的最简单的示例。

这对我有用!非常感谢。我只有一个问题,就是当程序完成后,文件为空(它们已经有数据了 - 被程序使用)。为什么会这样? - MattS
MattS:我稍微更新了一下代码,之前的流处理存在一些问题(我没有充分考虑到流处理)。这些更改可能会有所帮助。还添加了一些注释。 - pb2q
@pb1q 很好,我稍后会看一下。在之前的代码中,我确实记得关闭了输入/输出流,但是我忘记关闭进程的错误流,这导致了由于同时打开太多文件而崩溃。再次感谢。 - MattS

0
你尝试过使用 System.setIn 和 System.setOut 吗?这个方法从 JDK 1.0 开始就存在了。
public class MyClass
{
    System.setIn( new FileInputStream( "fileIn.txt" ) );
    int oneByte = (char) System.in.read();
    ...

    System.setOut( new FileOutputStream( "fileOut.txt" ) );
    ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接