programing

ProcessBuilder와 Runtime.exec()의 차이점

firstcheck 2022. 10. 18. 21:59
반응형

ProcessBuilder와 Runtime.exec()의 차이점

자바 코드에서 외부 명령어를 실행하려고 합니다만, 다른 점이 있습니다.Runtime.getRuntime().exec(...)그리고.new ProcessBuilder(...).start().

사용시Runtime:

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

exitValue는 0이고 명령어는 ok로 종료됩니다.

단,ProcessBuilder:

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

exit 값은 1001 이며 명령어는 중간에 종료됩니다.waitFor돌아온다.

문제를 해결하려면 어떻게 해야 합니까?ProcessBuilder?

의 다양한 과부하Runtime.getRuntime().exec(...)문자열 배열 또는 단일 문자열을 사용합니다.의 싱글 스트링 과부하exec()문자열 배열을 다음 중 하나에 전달하기 전에 문자열이 인수 배열로 토큰화됩니다.exec()string 배열이 필요한 오버로드입니다.ProcessBuilder반면 컨스트럭터는 문자열의 varargs 배열 또는 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 -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);

와는 차이가 없다.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

어떻게 하는지 보세요.Runtime.getRuntime().exec()String 명령어를 에 전달합니다.ProcessBuilder. 토큰라이저를 사용하여 명령어를 개별 토큰으로 확장한 후 호출합니다.exec(String[] cmdarray, ......)그 결과,ProcessBuilder.

를 구축하면ProcessBuilder하나의 문자열이 아닌 일련의 문자열을 사용하면 동일한 결과를 얻을 수 있습니다.

ProcessBuilder컨스트럭터는String...varararg에서는 명령어 전체를1개의 String으로 전달하면 단말기에서 따옴표로 둘러싸인 명령어를 호출하는 것과 같은 효과가 있습니다.

shell$ "command with args"

네, 차이가 있어요.

  • 메서드에는 명령어와 일련의 인수로 분할되는 단일 명령 문자열이 사용됩니다.

  • 컨스트럭터는 문자열의 (varargs) 배열을 취합니다.첫 번째 문자열은 명령어 이름이고 나머지 문자열은 인수입니다.(문자열 목록을 가져오는 대체 생성자가 있지만 명령어와 인수로 구성된 단일 문자열을 사용하는 생성자는 없습니다.)

따라서 ProcessBuilder에게 지시하는 것은 이름에 공백 및 기타 정크 항목이 포함된 "명령어"를 실행하는 것입니다.물론 운영체제는 해당 이름의 명령을 찾을 수 없으며 명령 실행은 실패합니다.

언급URL : https://stackoverflow.com/questions/6856028/difference-between-processbuilder-and-runtime-exec

반응형