首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 執行外部程式完整教學:Runtime.exec 與 ProcessBuilder 實戰

     編輯:Java 相關知識

一、啟動外部程式的兩種方式

  • Runtime.getRuntime().exec(...) —— 傳統 API,方法多載豐富。
  • ProcessBuilder.start() —— JDK 1.5+ 推薦,物件導向、支援更靈活的環境變數與工作目錄設定。

注意:僅能啟動實際存在的可執行檔,Shell 內建指令(如 dir, echo)需透過 cmd.exe /C 包裝。

二、核心類別 Process

無論哪種啟動方式,皆回傳 Process 物件代表子進程,提供:

  • getInputStream():讀取子進程標準輸出。
  • getErrorStream():讀取子進程錯誤輸出。
  • getOutputStream():向子進程標準輸入寫入資料。
  • waitFor():阻塞等待子進程結束,回傳退出碼。
  • exitValue():非阻塞取得退出碼,若進程未結束拋出例外。
  • destroy():嘗試終止子進程(不保證成功)。

三、避免阻塞與死鎖的關鍵技巧

子進程若同時輸出標準與錯誤流,且 Java 端只讀取其中一個,另一個緩衝區填滿會導致子進程阻塞,造成雙方死鎖。解決方案:

  1. 合併錯誤流到標準流:pb.redirectErrorStream(true),只需讀取單一流。
  2. 使用多執行緒並行讀取:分別建立執行緒消費 getInputStream() 與 getErrorStream()。
  3. 先讀取輸出再呼叫 waitFor():避免在讀取前阻塞等待。

四、完整範例:ProcessBuilder + redirectErrorStream + 多執行緒

// 範例 1:合併流 + 同步讀取
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", "dir");
pb.directory(new File("C:\\"));
pb.redirectErrorStream(true);
Process p = pb.start();
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
    String line;
    while ((line = br.readLine()) != null) System.out.println(line);
}
int exitCode = p.waitFor();

// 範例 2:多執行緒分別消費 stdout/stderr
class StreamWatch extends Thread {
    private final InputStream is; private final String type;
    private final List output = new ArrayList<>();
    StreamWatch(InputStream is, String type) { this.is = is; this.type = type; }
    public void run() {
        try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
            String line; while ((line = br.readLine()) != null) output.add(line);
        } catch (IOException e) { e.printStackTrace(); }
    }
    public List getOutput() { return output; }
}

// 使用
Process p = new ProcessBuilder("cmd.exe", "/c", "dir").start();
StreamWatch out = new StreamWatch(p.getInputStream(), "OUT");
StreamWatch err = new StreamWatch(p.getErrorStream(), "ERR");
out.start(); err.start();
int code = p.waitFor();
System.out.println("OUT: " + out.getOutput());
System.out.println("ERR: " + err.getOutput());

五、在 Java 中執行另一個 Java 程式

關鍵:取得 java.home 定位 java.exe,設定 -classpath,傳入主類別名與參數。

String java = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
String cp = System.getProperty("java.class.path");
List cmd = Arrays.asList(java, "-classpath", cp, MyTest.class.getName(), "arg1", "arg2");
ProcessBuilder pb = new ProcessBuilder(cmd);
// ... 後續同前述處理輸出流
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved