程式扎記: [ Java 常見問題 ] 執行外部程式等不到 Return code.

標籤

2010年9月12日 星期日

[ Java 常見問題 ] 執行外部程式等不到 Return code.

轉載自 這裡 
前言 : 
程式因為某種需要要去呼叫外部程式, 要等待外部程式執行完後再繼續進行, 如下所示 : 

- 部分範例代碼 :
  1. Runtime rt = Runtime.getRuntime();  
  2. Process proc = rt.exec(exec);  
  3. System.out.println("Retrun Code:" + proc.waitFor());  

但是執行外部程式時,程式的控制權就不再我手上,會一直waitFor(). 導致我的程式無法再繼續往下走. 

解法 : 
之前整好我也遇到這個問題. Runtime().exec()的 waitFor需要把inputStream和errorStream清空才會把控制權給你,否則就一直在wait中. 底下是摘自《More Java pitfalls 中文版》上的例子 : 
- BadExecJava2.java 代碼 :
  1. package test;  
  2.   
  3. import java.util.*;  
  4. import java.io.*;  
  5.   
  6. public class BadExecJava2 {  
  7.     public static void main(String args[]) {  
  8.         try {  
  9.             Runtime rt = Runtime.getRuntime();  
  10.             Process proc = rt.exec("javac");  
  11.             int exitVal = proc.waitFor();  
  12.             System.out.println("Process exitValue: " + exitVal);  
  13.         } catch (Throwable t) {  
  14.             t.printStackTrace();  
  15.         }  
  16.     }  
  17. }  

我們知道javac 命令,當不帶參數運行javac 程序時,它將輸出幫助說明,為什麼上面程序不產生任何輸出並掛起,永不完成呢?java文檔上說,由於有些本地平台為標准輸入和輸出流所提供的緩沖區大小有限,如果不能及時寫入子進程的輸入流或者讀取子進程的輸出流,可能導致子進程阻塞,甚至陷入死鎖。所以,上面的程序應改寫為 : 
- MediocreExecJavac.java 代碼 :
  1. package test;  
  2.   
  3. import java.io.*;  
  4.   
  5. public class MediocreExecJavac {  
  6.     public static void main(String args[]) {  
  7.         try {  
  8.             Runtime rt = Runtime.getRuntime();  
  9.             Process proc = rt.exec("javac");  
  10.             InputStream stderr = proc.getErrorStream();  
  11.             InputStreamReader isr = new InputStreamReader(stderr);  
  12.             BufferedReader br = new BufferedReader(isr);  
  13.             String line = null;  
  14.             System.out.println("");  
  15.             while ((line = br.readLine()) != null)  
  16.                 System.out.println(line);  
  17.             System.out.println("");  
  18.             int exitVal = proc.waitFor();  
  19.             System.out.println("Process exitValue: " + exitVal);  
  20.         } catch (Throwable t) {  
  21.             t.printStackTrace();  
  22.         }  
  23.     }  
  24. }  

下面是正確的輸出 : 
- 執行輸出 :

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
-J Pass directly to the runtime system

Process exitValue: 2

下面是一個更一般的程序,它用兩個線程同步清空標准錯誤流和標准輸出流,並能根據你所使用的windows操作系統選擇windows命令解釋器command.com或cmd.exe,然後執行你提供的命令 : 
- StreamGobbler.java 代碼 :
  1. package test;  
  2.   
  3. import java.util.*;  
  4. import java.io.*;  
  5.   
  6. class StreamGobbler extends Thread {  
  7.     InputStream is;  
  8.     String type; // 輸出流的類型ERROR或OUTPUT  
  9.   
  10.     StreamGobbler(InputStream is, String type) {  
  11.         this.is = is;  
  12.         this.type = type;  
  13.     }  
  14.   
  15.     public void run() {  
  16.         try {  
  17.             InputStreamReader isr = new InputStreamReader(is);  
  18.             BufferedReader br = new BufferedReader(isr);  
  19.             String line = null;  
  20.             while ((line = br.readLine()) != null) {  
  21.                 System.out.println(type + ">" + line);  
  22.                 System.out.flush();  
  23.             }  
  24.         } catch (IOException ioe) {  
  25.             ioe.printStackTrace();  
  26.         }  
  27.     }  
  28. }  
- GoodWindowsExec.java 代碼 :
  1. package test;  
  2.   
  3. public class GoodWindowsExec {  
  4.     public static void main(String args[]) {  
  5.         if (args.length < 1) {  
  6.             System.out.println("USAGE: java GoodWindowsExec ");  
  7.             System.exit(1);  
  8.         }  
  9.   
  10.         try {  
  11.             String osName = System.getProperty("os.name");  
  12.             System.out.println("osName: " + osName);  
  13.             String[] cmd = new String[3];  
  14.   
  15.             if (osName.equals("Windows XP") || osName.equals("Windows 2000")) {  
  16.                 cmd[0] = "cmd.exe";  
  17.                 cmd[1] = "/C";  
  18.                 cmd[2] = args[0];  
  19.             } else if (osName.equals("Windows 98")) {  
  20.                 cmd[0] = "command.com";  
  21.                 cmd[1] = "/C";  
  22.                 cmd[2] = args[0];  
  23.             }  
  24.   
  25.             Runtime rt = Runtime.getRuntime();  
  26.             System.out.println("Execing " + cmd[0] + " " + cmd[1] + " "  
  27.                     + cmd[2]);  
  28.             Process proc = rt.exec(cmd);  
  29.             // any error message?  
  30.             StreamGobbler errorGobbler = new StreamGobbler(proc  
  31.                     .getErrorStream(), "ERROR");  
  32.             // any output?  
  33.             StreamGobbler outputGobbler = new StreamGobbler(proc  
  34.                     .getInputStream(), "OUTPUT");  
  35.   
  36.             // kick them off  
  37.             errorGobbler.start();  
  38.             outputGobbler.start();  
  39.   
  40.             // any error???  
  41.             int exitVal = proc.waitFor();  
  42.             System.out.println("ExitValue: " + exitVal);  
  43.   
  44.         } catch (Throwable t) {  
  45.             t.printStackTrace();  
  46.         }  
  47.     }  
  48. }  

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!