ProcessBuilder可以用来运行外部应用程序。在我使用过程中发现了一些需要注意的地方,这些小问题也着实费了我很长时间去调试。不过既然知道了,就最好写出来,避免后来者再次出错。
首先,尽管ProcessBuilder可以用来运行外部程序,但不是所有能在shell中执行的命令都能被ProcessBuilder完美执行。以Windows系统为例,Windows批处理程序中常使用输出流/输入流/出错流的重定向运算符,其中'<'用来将右边的运算数作为左边运算数的输入;'>'或'1>'用来将右边的运算数作为左边运算数的标准输出(不包括错误输出);'2>'用来将右边的运算数作为左边运算数的错误输出;'[src] > [target] 2>&1'用来将[target]作为[src]的标准输出和错误输出。遗憾的是,这些重定向运算符在ProcessBuilder中都不能用,当然在Runtime.getRuntime().exec()中也同样不能用。要想达到同样的效果,在ProcessBuilder中需要用redirectOutput()方法和redirectError方法,以及将出错流合并到输出流的redirectErrorStream()方法。
第二,在ProcessBuilder中,不论是使用其构造方法,还是构造后通过commands(...)方法后期修改命令,命令都是以列表的形式接收的。按照Java文档所述,列表的第一个元素是应用程序名,剩余的元素是其命令行参数。若熟悉Windows命令行,可以知道要想使windows将含有空格的参数作为一个整体看待,这个参数需要用双引号括起来。用双引号括起来这个操作在ProcessBuilder中是不需要的!据我观察发现,ProcessBuilder有一种机制,即使某一参数中含有空格,它也能使windows认为那是一个参数。如下所示:
ProcessBuilder pb = new ProcessBuilder(
"MyExternalApplication.exe",
"FirstArgument",
"SecondArgument",
"Third Argument With Space In Between");
pb.start();
这段代码的作用和以下windows命令行的作用是一样的(假设Java虚拟机的当前工作目录和windows命令行的工作目录相同)
MyExternalApplication.exe FirstArgument SecondArgument "Third Argument With Space In Between"