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

2022-08-31 09:53:04

我正在尝试从java代码执行外部命令,但是我注意到和.之间有一个区别。Runtime.getRuntime().exec(...)new ProcessBuilder(...).start()

使用时 :Runtime

Process p = Runtime.getRuntime().exec(installation_path + 
                                       uninstall_path + 
                                       uninstall_command + 
                                       uninstall_arguments);
p.waitFor();

退出值为 0,命令终止正常。

但是,使用:ProcessBuilder

Process p = (new ProcessBuilder(installation_path +    
                                 uninstall_path +
                                 uninstall_command,
                                 uninstall_arguments)).start();
p.waitFor();

退出值为 1001,命令在中间终止,但返回。waitFor

我该怎么做才能解决问题?ProcessBuilder


答案 1

的各种重载要么采用字符串数组,要么采用单个字符串。的单字符串重载会将字符串标记为参数数组,然后将字符串数组传递到采用字符串数组的重载之一。另一方面,构造函数只采用字符串的 varargs 数组或字符串的 varargs 数组,其中数组或列表中的每个字符串都假定为单个参数。无论哪种方式,获得的参数都会被合并到一个字符串中,该字符串被传递给操作系统以执行。Runtime.getRuntime().exec(...)exec()exec()ProcessBuilderList

因此,例如,在Windows上,

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

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

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

将失败,除非碰巧有一个程序的名称位于 中。这是因为没有标记化:假定要运行的命令已被标记化。相反,您应该使用DoStuff.exe -arg1 -arg2C:\

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

答案 2

没有区别,因为 实现是: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的评论


推荐