Java程式執行系統命令

Acelin_H發表於2021-07-15

今天接到一個任務,要用第三方提供的一個jar包來進行檔案的加解密,需要使用“java -jar”命令執行jar包來對檔案進行加解密操作,順便記錄一下兩種實現方式


Process類


首先了解一下Process類,顧名思義,這個類叫程式類,封裝了一個程式(即一個執行程式)。

官方解釋:
Process類提供了執行程式輸入、執行輸出到程式、等待程式完成、檢查程式退出狀態以及銷燬(殺死)程式的方法。

提供了6個抽象方法

  • public abstract OutputStream getOutputStream(); 返回連線到子程式正常輸入的輸出流

  • public abstract InputStream getInputStream(); 返回連線到子程式正常輸出的輸入流

  • public abstract InputStream getErrorStream(); 返回連線到子程式錯誤輸出的輸入流

  • public abstract int waitFor() throws InterruptedException; 使當前執行緒在必要時等待,直到此Process物件表示的Process終止

  • public abstract int exitValue(); 此Process物件表示的子流程的退出值。 按照慣例,值0表示正常終止。丟擲IllegalThreadStateException的話表示此Process物件表示的子Process尚未終止

  • public abstract void destroy(); 殺死子程式。 此Process物件表示的子流程是否被強制終止取決於實現

1.8版本後新增以下三個公共方法

public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException{
	long startTime = System.nanoTime();
    long rem = unit.toNanos(timeout);

    do {
        try {
            exitValue();
            return true;
        } catch(IllegalThreadStateException ex) {
            if (rem > 0)
                Thread.sleep(
                    Math.min(TimeUnit.NANOSECONDS.toMillis(rem) + 1, 100));
        }
        rem = unit.toNanos(timeout) - (System.nanoTime() - startTime);
    } while (rem > 0);
    return false;
}

public Process destroyForcibly() {
    destroy();
    return this;
}

public boolean isAlive() {
    try {
        exitValue();
        return false;
        } catch(IllegalThreadStateException e) {
            return true;
        }
    }
}

一、使用Runtime.exec()


回到原來的話題,執行“java -jar"命令執行jar包進行加解密。我先是用Runtime.exec() 方法建立一個本機程式,並返回 Process 子類的一個例項的方式來實現,來看下程式碼:

String command = "java -jar D:/work/si-tech/project/cbn/lib/acctmgr-application/jfycrpto.jar DEC 8613052000078705_001_003_20200115_689814_I.TXT";

try{
    Process p = Runtime.getRuntime().exec(command);

    InputStream is = p.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    String outInfo;
    while ((outInfo = reader.readLine()) != null) {
        System.out.println(outInfo);
    }

    p.waitFor(); // 等待process子程式終止
    return p.exitValue() == 0;

}catch (Exception e){
    log.error("{}{}失敗",fileName, encrypt ? "加密" : "解密");
    return false;
}

二、使用ProcessBuilder


後來瞭解到,從 1.5 開始, ProcessBuilder.start()是建立Process的首選方式,於是最終改成如下方式:

/* 命令用List儲存 */
String[] commandSplit = command.split(" ");
List<String> lcommand = new ArrayList<>(Arrays.asList(commandSplit));

ProcessBuilder processBuilder = new ProcessBuilder(lcommand);
processBuilder.redirectErrorStream(true); // 此物件的start()方法隨後啟動的子程式生成的任何錯誤輸出都將與標準輸出合併,以便可以使用Process.getInputStream()方法讀取兩者
try{
    Process process = processBuilder.start();
    InputStream is = process.getInputStream();
    BufferedReader bs = new BufferedReader(new InputStreamReader(is));

    process.waitFor(); // 等待process子程式終止

    String line = null;
    while ((line = bs.readLine()) != null) {
        System.out.println(line);
    }

    return process.exitValue() == 0;
}catch (Exception e){
    log.error("{}{}失敗",fileName, encrypt ? "加密" : "解密");
    return false;
}

相關文章