代码之家  ›  专栏  ›  技术社区  ›  Ivan Mushketyk

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

  •  6
  • Ivan Mushketyk  · 技术社区  · 14 年前

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

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

    我想从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 回复  |  直到 8 年前
        1
  •  2
  •   Grodriguez    14 年前

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

    OutputStream out = proc.getOuptutStream();
    

    这个输出流通过管道传输到进程的标准输入流中,因此您可以直接写入它(也许您希望将它包装在 PrintWriter 首先)将数据发送到进程的stdin。

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

    API参考:

        2
  •  0
  •   Uhlen    14 年前

    在您的示例中,似乎while条件内部的转换失败了,这似乎工作得更好(我不运行suse,因此我没有尝试使用zyper):

    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);
    }
    
        3
  •  0
  •   Martin Algesten    14 年前

    我最近把google闭包编译器包装成一个.jar文件,在一个过程中提取并使用它。此编译器仅通过system.in/out/err进行对话。在将管道连接在一起时有一个很大的“gotcha”,这在javadoc过程中只是简单地提到。

    “…未能及时写下 输入流或读取输出流 子流程可能导致 要阻塞的子进程,甚至 死锁。”

    在MacOSX上,缓冲区是16K,如果您没有按照建议立即读取,进程就会死锁。我唯一能解决这个问题的方法是ATM,这是一个相当讨厌的忙碌等待。

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