표준적인 ProcessBuilder 사용법은 아래 펼치기를 참고펼치기/접기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // Process 관련 설정 File path = new File("프로세스가/실행될/디렉토리/경로"); ArrayList<String> commandList = new ArrayList<>(); // 명령어 설정 commandList.add("명령어1"); commandList.add("명령어2"); commandList.add("명령어3"); // ProcessBuilder 생성 ProcessBuilder pb = new ProcessBuilder(); // ProcessBuilder 설정 pb.directory(path); pb.command(commandList); // Process 실행 Process p = pb.start(); // Buffered Reader로 실행 내용 읽어오기 BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), "UTF-8")); String line; while ((line = br.readLine()) != null){ System.out.println(">>> " + line); }
1. Process Builder, Process
Process Builder 클래스는 자바에서 외부 프로세스를 생성하고 제어할 수 있는 도구입니다.
쉽게 말해 자바로 외부 프로그램을 실행시킬 수 있는 방법 중 하나입니다.
그리고 Process 클래스는 Process Builder 를 통해 생성된 프로세스를 나타내는 추상 클래스입니다.
Process Builder를 통해 생성된 프로세스의 상태 제어, 입출력 등의 관리가 가능합니다.
아래에 간단한 예시를 들겠습니다.
1-1. 예시
먼저, 자바를 통해 실행시킬 간단한 python 파일을 만듭니다.
이 파일은 두 개의 문장을 출력합니다.
1
2
3
# ** 파일명 : python_ex.py
print("test 입니다.")
print("process builder가 정상적으로 실행되었습니다.")
java에서 ProcessBuilder를 통해 python 파일을 실행시키는 Process를 생성하고,
이 프로세스를 실행 시킵니다.
그리고 BufferReader로 실행 결과를 받도록 합니다.
자세한 내용은 아래에서 다룰테니, 지금은 작동과 결과만 보도록 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ** 파일명 : example_processbuilder.java
// 파이썬 경로를 path 변수에 저장
String path = "User/Desktop/python_ex.py"
// Process Builder로 실행될 프로세스 선언
ProcessBuilder pb = new ProcessBuilder("python", path);
// 외부 프로세스 시작
Process p = pb.start();
// 프로세스 실행 결과를 받아오기
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), "UTF-8"));
String line;
while ((line = br.readLine()) != null){
System.out.println(">>> " + line);
}
// 자바가 실행됐다는 증거로 print
System.out.println("process 실행이 완료되었습니다.")
자바파일을 실행시킨 결과는 아래와 같습니다.
1
2
3
4
// 실행 결과
>>> 파이썬 파일을 실행합니다.
>>> test입니다.
>>> process 실행이 완료되었습니다.
1-2. Process Builder 와 Process 의 관계
위 예시에서 사용된 Process Builder와 Process의 관계를 추가로 설명해보도록 하겠습니다.
ProcessBuilder 클래스는 Java 파일이 실행되는 것 외적으로 프로세스를 생성하기 위해 사용하는 툴입니다.
이 클래스 객체는 terminal에 입력하는 명령어들을 파라미터로 갖을 수 있습니다.
그리니까.. “터미널에서 입력할 내용을 담고 있는 그릇” 이라고 생각하면 편할 것입니다.
다르게 말해보자면 “실행할 프로세스 명령어를 담고있는 그릇”으로도 말할 수 있겠습니다.
예를 들어 ProcessBuilder("python", "/User/Desktop/python_ex.py")
라는 ProcessBuilder 객체는
Desktop에 있는 python_ex.py 파이썬 파일을 실행
하는 명령어를 담고 있는 것이죠.
Process 클래스는 ProcessBuilder 클래스를 시작(.start()) 하는 것으로 만들어지게 됩니다.
이 클래스 객체는 현재 Java 파일이 실행되는 외부에 만들어진 Process를 가리키고(=추상화하고) 있습니다.
위에서 예를 든 ProcessBuilder(“python”, “/User/Desktop/python_ex.py”) 객체를 .start()하여 만들어진 Process 객체
는
python_ex.py 파일이 실행되는 작업 자체
를 의미합니다.
정리해보자면 ProcessBuilder 객체는 “앞으로 실행할 작업의 정보를 담고 있는” 객체이고,
Process 객체는 “실행되고 있는 작업을 추상화한” 객체입니다.
2. ProcessBuilder 클래스 설명
앞서 설명했듯 “앞으로 실행할 작업(Process)의 정보를 담고 있는” 객체입니다.
그리고, .start() 메서드를 통해 그 작업을 실행시킬 수도 있습니다.
2-1. ProcessBuilder 클래스 선언
ProcessBuilder 클래스의 선언은 일반적인 객체 선언과 동일한 형태로 진행됩니다.
그리고 선언될 때의 파라미터는 String 형태와 List 형태 두 가지를 사용할 수 있습니다.
1
2
// String 형태의 파라미터를 사용하는 경우
ProcessBuilder pb1 = new ProcessBuilder("명령어1", "명령어2", "명령어3" ...)
1
2
3
4
5
6
7
// List 형태의 파라미터를 사용하는 경우
ArrayList<String> l1 = new ArrayList<>();
l1.add("명령어1")
l1.add("명령어2")
l1.add("명령어3")
...
ProcessBuilder pb2 = new ProcessBuilder(l1);
1
2
3
4
// 그리고 ProcessBuilder 객체를 먼저 생성하고,
// 나중에 command 를 설정할 수도 있습니다.
ProcessBuilder pb3 = new ProcessBuilder();
pb3.command("명령어1", "명령어2" ...);
두 방법 중 무엇이 좋고 나쁜 것은 없어 보입니다. 단지 상황에 맞춰 사용하면 되겠습니다.
명령어가 짧고 적을 경우 String 형태를, 명령어가 길거나 많을 경우 ArrayList 형태를 사용하면 좋겠습니다.
2-2. ProcessBuilder 클래스의 메서드
다음은 ProcessBuilder 클래스의 메서드(method)들입니다.
여기서 ‘외부 Process’란 ProcessBuilder.start()를 통해 만들어진 Process를 의미합니다.
Method | 파라미터타입 | 설명 | 반환값 |
---|---|---|---|
start() | 설정된 명령어와 인수, 작업 디렉토리 등을 바탕으로 외부 Process를 시작합니다. |
Process 객체 | |
command(String …) | String/ArrayList | 외부 Process를 실행하기 위한 명령어와 인수를 설정합니다. |
|
directory(file) | File | 외부 Process가 실행될 작업 디렉토리를 설정합니다. | |
environment() | 외부 Process가 실행될 때 사용되는 환경 변수를 설정하기 위한 Map 객체를 반환 |
Map<String, String> | |
inheritIO() | 현재 자바 프로세스의 표준 입출력, 에러 스트림을 외부 프로세스와 공유해 리디렉션 |
||
redirectInput() | ProcessBuilder.Redirect source |
외부 Process의 표준 입력을 지정된 소스로 리디렉션 | |
redirectOutput() | ProcessBuilder.Redirect destination |
외부 Process의 표준 출력을 지정된 대상으로 리디렉션 | |
redirectError() | ProcessBuilder.Redirect destination |
외부 Process의 표준 에러를 지정된 대상으로 리디렉션 |
directory 클래스에서 사용되는 file 클래스에 대해서는 아래 포스트를 참고해주세요.
포스트 링크 : Java file class
2-3. ProcessBuilder 클래스의 속성
다음은 ProcessBuilder 클래스의 속성(attribute)들입니다.
여기서 ‘외부 Process’란 ProcessBuilder.start()를 통해 만들어진 Process를 의미합니다.
Attribute | 설명 | 타입 |
---|---|---|
command() | 외부 Process의 명령어와 인수를 저장한 리스트 | List |
directory() | 외부 Process가 실행될 작업 디렉토리 | File |
environment() | 외부 Process가 실행될 때 사용되는 환경 변수 | Map<String, String> |
redirectErrorStream() | 표준 에러 스트림을 표준 출력 스트림으로 리디렉션할지 여부 | Boolean |
2-4. ProcessBuilder method와 attribute 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class example{
public static void main(String[] args) throws IOException{
ProcessBuilder pb = new ProcessBuilder(); // ProcessBuilder 생성
File path = new File("/User/Desktop/"); // Process 실행될 경로
String fileName = "./example.py"; // 실행시킬 파일명
pb.directory(path); // Process 가 실행되는 경로 지정
pb.command("python", fileName); // Process command 지정
Process p = pb.start(); // Process 실행
System.out.println("커맨드 : " + pb.command());
// >>> 커맨드 : [python, ./example.py]
System.out.println("디렉토리 : " + pb.directory());
// >>> 디렉토리 : /User/Desktop
System.out.println("환경변수 : " + pb.environment());
// >>> 환경변수 : {LOCAL_GIT_DIRECTORY:/APPLICATION .... 생략}
System.out.println("에러스트림 리디렉션 : " + pb.redirectErrorStream());
// >>> 에러스트림 리디렉션 : false (지정하지 않음)
}
}
2-5. Exception이 필요한 이유
ProcessBuilder 클래스를 사용할 때에는 꼭 예외처리를 사용해야 합니다.
예외처리가 되지 않는 경우엔 unhandeled exception이 발생하게 되며, 실행이 불가합니다.
예외처리를 하는 이유는, 실행시키려는 프로세스가 어떤 오류를 발생했을 경우에 Java 프로세스의 향방을 정해야 하기 때문이죠.
예외처리는 (1) ProcessBuilder 의 실행부(.start()) 에서 try-catch 문을 사용하거나
(2) ProcessBuilder를 사용하는 클래스의 main 메서드에서 throws Exception을 사용하면 됩니다.
두 가지 방법 중 하나를 상황에 맞게 사용하면 되겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// try-catch 문 사용
public class example_processbuilder{
public static void main(Stinrg[] args){
ProcessBuilder pb = new ProcessBuilder("cd", "User/Desktop");
// try-catch
try {
Process p = pb.start();
} catch (IOException | InterruptedException e){
e.printStackTrace();
}
}
}
1
2
3
4
5
6
7
8
9
10
// throws Exception 사용
public class example_processbuilder{
// throws Exception
public static void main(String[] args) throws IOException{
ProcessBuilder pb = new ProcessBuilder("cd", "User/Desktop");
Process p = pb.start();
}
}
3. Process 클래스 설명
Process 클래스는 현재 Java가 실행되는 프로세스와 다른, 외부의 Process를 바라보는 추상 클래스입니다.
이 클래스로 외부 Process의 상태를 제어하고, 입출력, 에러 스트림 관리를 할 수 있습니다.
3-1. Process 클래스 선언
Process 클래스는 일반적으로 ProcessBuilder.start() 메서드 혹은 Runtime.exec() 메서드를 통해 생성됩니다.
ProcessBuilder는 위에서 설명했는데, Runtime은 뭐냐.
Runtime.exec()은 Java 1.7 미만의 버전에서 사용된 외부 프로세스 실행 메서드입니다.
1
2
ProcessBuilder pb = new ProcessBuilder("명령어1","명령어2"...);
Process p = ProcessBuilder.start();
3-2. Process 클래스의 속성
Attribute | 설명 | 타입 |
---|---|---|
Process.getInputStream() | 외부 Process의 표준 출력에 대한 입력 스트림 | InputStream |
Process.getOutputStream() | 외부 Process의 표준 입력에 대한 출력 스트림 | OutputStream |
Process.getErrorStream() | 외부 Process의 표준 에러에 대한 입력 스트림 | InputStream |
3-3. Process 클래스의 메서드
Method | 파라미터타입 | 설명 | 반환값 |
---|---|---|---|
.waitFor() | 외부 Process의 종료를 기다리고, 종료 코드를 반환 | int | |
waitFor() 사용시 해당 프로세스 종료까지 타작업 불가 | |||
waitFor() 미사용시 프로세스 실행만 시키고 손뗌 | |||
.destory() | 외부 Process를 강제 종료시킨다. | void | |
.isAlive() | 외부 Process가 실행중인지 여부 반환 | boolean | |
.exitValue() | 외부 Process의 종료 코드를 반환 이 메서드 전에 .waitFor()메서드를 사용해 Process가 종료되기를 기다려야 한다. |
int |
3-4. Process method와 attribute 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class example{
public static void main(String[] args) throws IOException{
ProcessBuilder pb = new ProcessBuilder("명령어1", "명령어2"); // ProcessBuilder 생성
Process p = pb.start(); // Process 실행, 생성
System.out.println(p.getInputStream());
// >>> java.lang.ProcessImpl$ProcessPipeInputStream@27c170f0
System.out.println(p.getOutputStream());
// >>> java.lang.ProcessImpl$ProcessPipeOutputStream@5451c3a8
System.out.println(p.getErrorStream());
// >>> java.lang.ProcessImpl$ProcessPipeInputStream@2626b418
System.out.println(p.isAlive());
// >>> false : 프로세스가 종료됨
p.destroy(); // 프로세스를 강제 종료
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class example{
public static void main(String[] args) throws IOException, InterruptedException{
// 계속 켜져있는 블로그 프로세스를 외부 프로세스로 바라보도록 하고
Process p = Runtime.getRuntime().exec(file);
// While : 프로세스가 살아있다면(true) 그리고 i 가 5 이하라면
while (p.isAlive()){
System.out.println("External process is running..."); // 정해진 문구 출력
Thread.sleep(1000); // 1000ms (1초) 대기
}
// 프로세스가 종료되었을 때 종료코드 출력
System.out.println("External process exited with code: " + p.exitValue());
}
}
// 출력 내용
// >>> External process is running...
// >>> External process is running...
// >>> External process is running...
// >>> ...
// >>> External process exited with code : 0 (프로세스 종료되었을 때)
4. Reference
개인 실험
Java의 정석 (남궁성)
자바로 외부 프로그램 실행시키기 : https://yangyag.tistory.com/55
Java 파일 입출력, 파일 경로 : https://chb2005.tistory.com/57
ProcessBuilder 클래스 : https://happygrammer.github.io/java/processbuilder/
chatGPT (교차검증)