前言 :
程式因為某種需要要去呼叫外部程式, 要等待外部程式執行完後再繼續進行, 如下所示 :
- 部分範例代碼 :
- Runtime rt = Runtime.getRuntime();
- Process proc = rt.exec(exec);
- System.out.println("Retrun Code:" + proc.waitFor());
但是執行外部程式時,程式的控制權就不再我手上,會一直waitFor(). 導致我的程式無法再繼續往下走.
解法 :
之前整好我也遇到這個問題. Runtime().exec()的 waitFor需要把inputStream和errorStream清空才會把控制權給你,否則就一直在wait中. 底下是摘自《More Java pitfalls 中文版》上的例子 :
- BadExecJava2.java 代碼 :
- package test;
- import java.util.*;
- import java.io.*;
- public class BadExecJava2 {
- public static void main(String args[]) {
- try {
- Runtime rt = Runtime.getRuntime();
- Process proc = rt.exec("javac");
- int exitVal = proc.waitFor();
- System.out.println("Process exitValue: " + exitVal);
- } catch (Throwable t) {
- t.printStackTrace();
- }
- }
- }
我們知道javac 命令,當不帶參數運行javac 程序時,它將輸出幫助說明,為什麼上面程序不產生任何輸出並掛起,永不完成呢?java文檔上說,由於有些本地平台為標准輸入和輸出流所提供的緩沖區大小有限,如果不能及時寫入子進程的輸入流或者讀取子進程的輸出流,可能導致子進程阻塞,甚至陷入死鎖。所以,上面的程序應改寫為 :
- MediocreExecJavac.java 代碼 :
- package test;
- import java.io.*;
- public class MediocreExecJavac {
- public static void main(String args[]) {
- try {
- Runtime rt = Runtime.getRuntime();
- Process proc = rt.exec("javac");
- InputStream stderr = proc.getErrorStream();
- InputStreamReader isr = new InputStreamReader(stderr);
- BufferedReader br = new BufferedReader(isr);
- String line = null;
- System.out.println("
" );- while ((line = br.readLine()) != null)
- System.out.println(line);
- System.out.println("");
- int exitVal = proc.waitFor();
- System.out.println("Process exitValue: " + exitVal);
- } catch (Throwable t) {
- t.printStackTrace();
- }
- }
- }
下面是正確的輸出 :
- 執行輸出 :
Usage: javac
where possible options include:
-g Generate all debugging info
-g:none Generate no debugging info
...(中間省略)...
-Akey[=value] Options to pass to annotation processors
-X Print a synopsis of nonstandard options
-JPass directly to the runtime system
Process exitValue: 2
下面是一個更一般的程序,它用兩個線程同步清空標准錯誤流和標准輸出流,並能根據你所使用的windows操作系統選擇windows命令解釋器command.com或cmd.exe,然後執行你提供的命令 :
- StreamGobbler.java 代碼 :
- GoodWindowsExec.java 代碼 :
- package test;
- import java.util.*;
- import java.io.*;
- class StreamGobbler extends Thread {
- InputStream is;
- String type; // 輸出流的類型ERROR或OUTPUT
- StreamGobbler(InputStream is, String type) {
- this.is = is;
- this.type = type;
- }
- public void run() {
- try {
- InputStreamReader isr = new InputStreamReader(is);
- BufferedReader br = new BufferedReader(isr);
- String line = null;
- while ((line = br.readLine()) != null) {
- System.out.println(type + ">" + line);
- System.out.flush();
- }
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- }
- package test;
- public class GoodWindowsExec {
- public static void main(String args[]) {
- if (args.length < 1) {
- System.out.println("USAGE: java GoodWindowsExec
" );- System.exit(1);
- }
- try {
- String osName = System.getProperty("os.name");
- System.out.println("osName: " + osName);
- String[] cmd = new String[3];
- if (osName.equals("Windows XP") || osName.equals("Windows 2000")) {
- cmd[0] = "cmd.exe";
- cmd[1] = "/C";
- cmd[2] = args[0];
- } else if (osName.equals("Windows 98")) {
- cmd[0] = "command.com";
- cmd[1] = "/C";
- cmd[2] = args[0];
- }
- Runtime rt = Runtime.getRuntime();
- System.out.println("Execing " + cmd[0] + " " + cmd[1] + " "
- + cmd[2]);
- Process proc = rt.exec(cmd);
- // any error message?
- StreamGobbler errorGobbler = new StreamGobbler(proc
- .getErrorStream(), "ERROR");
- // any output?
- StreamGobbler outputGobbler = new StreamGobbler(proc
- .getInputStream(), "OUTPUT");
- // kick them off
- errorGobbler.start();
- outputGobbler.start();
- // any error???
- int exitVal = proc.waitFor();
- System.out.println("ExitValue: " + exitVal);
- } catch (Throwable t) {
- t.printStackTrace();
- }
- }
- }
沒有留言:
張貼留言