使用流重定向从Java代码启动外部可执行文件

时间:2010-11-20 10:39:26

标签: java stream outputstream

我需要以这样的方式启动外部可执行文件,即用户可以与刚刚启动的程序进行交互。

例如在OpenSuse Linux中有一个包管理器--Zypper。您可以在命令模式下启动zypper,并为其提供安装,更新,删除等命令。

我想以一种用户可以与之交互的方式从Java代码运行它:输入命令并查看他开始的程序的输出和错误。

这是我尝试使用的Java代码:

public static void main(String[] args) throws IOException, InterruptedException {
    Process proc = java.lang.Runtime.getRuntime().exec("zypper shell");

    InputStream stderr = proc.getInputStream();
    InputStreamReader isr = new InputStreamReader(stderr);
    BufferedReader br = new BufferedReader(isr);
    String line = null;
    char ch;

    while ( (ch = (char)br.read()) != -1)
        System.out.print(ch);

    int exitVal = proc.waitFor();
    System.out.println("Process exitValue: " + exitVal);
}

但不幸的是我只能看到它的输出:

zypper>

但无论我写什么,我的输入都不会影响已启动的程序。 我该怎么做?

3 个答案:

答案 0 :(得分:2)

您需要获取输出流才能写入流程:

OutputStream out = proc.getOuptutStream();

此输出流通过管道传输到流程的标准输入流中,因此您可以只写入它(可能您希望先将其包装在PrintWriter中),然后将数据发送到流程中标准输入。

请注意,获取错误流(proc.getErrorStream)以便读取进程写入其stderr的任何错误输出也可能很方便。

API参考:

答案 1 :(得分:0)

似乎在你的例子中,while while条件中的转换失败,这似乎更好(我没有运行Suse所以我没有尝试使用Zypper):

public static void main(String[] args) throws IOException, InterruptedException
{
    //Process proc = java.lang.Runtime.getRuntime().exec("zypper shell");
    Process proc = java.lang.Runtime.getRuntime().exec("ping -t localhost");

    InputStream stderr = proc.getInputStream();
    InputStreamReader isr = new InputStreamReader(stderr);
    BufferedReader br = new BufferedReader(isr);

    int i;
    while ( (i = br.read()) != -1)
    {
        System.out.print((char) i);
    }

    int exitVal = proc.waitFor();
    System.out.println("Process exitValue: " + exitVal);
}

答案 2 :(得分:0)

我最近将Google Closure Compiler包装成一个.jar文件,该文件在Process中被提取并使用。此编译器仅通过System.in/out/err进行通信。将管道连接在一起有一个很大的“陷阱”,这在Process javadoc中简要提到过。

  

“......未能及时写出来   输入流或读取输出流   子进程可能会导致   subprocess to block,甚至   死锁“。

在Mac OS X上,缓冲区为16k,如果您没有按照建议立即读取,则进程死锁。我解决这个问题的唯一办法就是忙碌的等待。

https://github.com/algesten/googccwrap/blob/master/src/main/java/googccwrap/GoogleClosureCompilerWrapper.java