ProcessBuilder和Runtime.exec()之间的区别

时间:2011-07-28 08:25:46

标签: java runtime.exec processbuilder

我正在尝试从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的问题?

4 个答案:

答案 0 :(得分:90)

Runtime.getRuntime().exec(...)的各种重载采用字符串数组或单个字符串。在将字符串数组传递到带有字符串数组的exec()重载之一之前,exec()的单字符串重载会将字符串标记为参数数组。另一方面,ProcessBuilder构造函数只接受字符串的varargs数组或字符串的List,其中数组或列表中的每个字符串都被假定为单个参数。无论哪种方式,获得的参数然后连接成一个字符串,传递给OS执行。

因此,例如,在Windows上,

Runtime.getRuntime().exec("C:\DoStuff.exe -arg1 -arg2");

将运行带有两个给定参数的DoStuff.exe程序。在这种情况下,命令行会被标记化并重新组合在一起。然而,

ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe -arg1 -arg2");

将失败,除非恰好在DoStuff.exe -arg1 -arg2中有一个名为C:\的程序。这是因为没有令牌化:假设运行的命令已被标记化。相反,你应该使用

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);

答案 1 :(得分:17)

查看Runtime.getRuntime().exec()如何将String命令传递给ProcessBuilder。它使用一个标记化器并将命令分解为单个标记,然后调用构造exec(String[] cmdarray, ......)的{​​{1}}。

如果使用字符串数组而不是单个字符串构造ProcessBuilder,则会得到相同的结果。

ProcessBuilder构造函数采用ProcessBuilder vararg,因此将整个命令作为单个String传递与在终端中的引号中调用该命令具有相同的效果:

String...

答案 2 :(得分:13)

是的,有区别。

所以你告诉ProcessBuilder要做的是执行一个名称中包含空格和其他垃圾的“命令”。当然,操作系统找不到具有该名称的命令,并且命令执行失败。

答案 3 :(得分:11)

ProcessBuilder.start()Runtime.exec()之间没有区别,因为Runtime.exec()的实施是:

public Process exec(String command) throws IOException {
    return exec(command, null, null);
}

public Process exec(String command, String[] envp, File dir)
    throws IOException {
    if (command.length() == 0)
        throw new IllegalArgumentException("Empty command");

    StringTokenizer st = new StringTokenizer(command);
    String[] cmdarray = new String[st.countTokens()];
    for (int i = 0; st.hasMoreTokens(); i++)
        cmdarray[i] = st.nextToken();
    return exec(cmdarray, envp, dir);
}

public Process exec(String[] cmdarray, String[] envp, File dir)
    throws IOException {
    return new ProcessBuilder(cmdarray)
        .environment(envp)
        .directory(dir)
        .start();
}

所以代码:

List<String> list = new ArrayList<>();
new StringTokenizer(command)
.asIterator()
.forEachRemaining(str -> list.add((String) str));
new ProcessBuilder(String[])list.toArray())
            .environment(envp)
            .directory(dir)
            .start();

应与:

相同
Runtime.exec(command)

感谢 dave_thompson_085 发表评论