ProcessBuilder和Runtime.exec()之间的区别
我试图从java代码执行一个外部命令,但是我注意到了Runtime.getRuntime().exec(...)
和new Process(...).start()
之间的区别。
使用Runtime
:
Process p = Runtime.getRuntime().exec(installation_path + uninstall_path + uninstall_command + uninstall_arguments); p.waitFor();
exitValue为0,命令终止。
但是,使用ProcessBuilder
:
Process p = (new ProcessBuilder(installation_path + uninstall_path + uninstall_command, uninstall_arguments)).start(); p.waitFor();
退出值是1001,命令终止在中间,虽然waitFor
返回。
我该怎么办才能解决ProcessBuilder
的问题?
Runtime.getRuntime().exec(...)
的各种重载可以是一个string数组,也可以是一个string。 exec()
的单个string重载将string标记为一个参数数组,然后将string数组传递给一个接受string数组的exec()
重载。 另一方面, ProcessBuilder
构造函数只采用可变长string数组或stringList
,其中数组或列表中的每个string被假定为单独的参数。 无论哪种方式,获得的参数然后join到传递给操作系统执行的string。
所以,例如,在Windows上,
Runtime.getRuntime().exec("C:\DoStuff.exe -arg1 -arg2");
将使用两个给定的参数运行DoStuff.exe
程序。 在这种情况下,命令行将被标记并放回到一起。 然而,
ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe -arg1 -arg2");
将会失败,除非在C:\
碰巧有名为DoStuff.exe -arg1 -arg2
的程序。 这是因为没有标记:要运行的命令已经被标记。 相反,你应该使用
ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe", "-arg1", "-arg2");
或者可选地
List<String> params = java.util.Arrays.asList("C:\DoStuff.exe", "-arg1", "-arg2"); ProcessBuilder b = new ProcessBuilder(params);
查看Runtime.getRuntime().exec()
将String命令传递给ProcessBuilder
。 它使用一个标记器并将这个命令分解成单独的标记,然后调用构造一个ProcessBuilder
exec(String[] cmdarray, ......)
。
如果你用一个string数组来构造ProcessBuilder
而不是一个,你会得到相同的结果。
ProcessBuilder
构造函数接受一个String...
vararg,因此将整个命令作为单个String传递与在terminal中引用该命令的效果相同:
shell$ "command with args"
是的,有一个区别。
-
Runtime.exec(String)
方法使用一个命令string将其分成一个命令和一系列参数。 -
ProcessBuilder
构造函数接受一个(可变参数)string数组。 第一个string是命令名称,其余的是参数。
所以你告诉ProcessBuilder要做的是执行一个名字中有空格和其他垃圾的“命令”。 当然,操作系统找不到具有该名称的命令,命令执行失败。