很多時候,我們需要呼叫系統命令來做些處理。比如,在程式中ping裝置是否能連線,執行資料庫的自動備份,以及程式的重啟。這時候我們必須要使用Process類來完成這些功能。 一般情況下,我們都會將命令執行過程中的資訊輸出,以便檢查問題。但有時候我們還需知道這個執行的程式在什麼時候結束,因為不僅要知道結束了,還要知道該程式完成時返回的結果。 可能會說,這些不都是API已經給提供好的嗎?過程中的訊息可以用process.getInputStream()獲取,程式最終結果可以由process.waitFor()得到。的確,這些看似可以辦到,但其實,裡面有陷阱。
首先以Runtime來建立我們需要的Process物件例子:
Java程式碼 收藏程式碼
Process process = null;
BufferedReader reader=null;
try {
process = Runtime.getRuntime().exec("ping 192.168.0.125");
reader=new BufferedReader(new InputStreamReader(process.getInputStream()));
String line=null;
while((line=reader.readLine())!=null){
System.out.println(line);
}
int result=process.waitFor();
System.out.println(result);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
複製程式碼
這個例子我們只是簡單的ping了一個IP,用getInputStream()輸出過程資訊,然後用process.waitFor()得到執行完成後的結果。會發現一點問題都沒有。 1.此時如果把process.getInputStream()換成process.getErrorStream(),就只有一個結果輸出了。 2.如果把執行的內容換成EXP導個oralce資料庫的命令呢!發現過程資訊和結果值都有,但是如果拿到一個server上去跑跑,又發現總是會報錯,rocess has not exited 程式未停止....在網上查詢,很多人會告訴你是輸出流導致程式阻塞,發生死鎖了。 3.此時你再把process.getErrorStream()改回process.getInputStream(),發現啥也沒有,而且程式不會停掉。這是肯定的,輸出流又導致程式阻塞了。 查API得知Process所有標準 io(即 stdin,stdout,stderr)操作都將通過三個流 (getOutputStream(),getInputStream(),getErrorStream()) 重定向到父程式。那為什麼執行系統自帶命令就能用getInputStream()獲取到資訊而不是系統自帶命令就一定要用getErrorStream()來獲取資訊呢!惑之...待高手解答... 獲取程式返回結果有兩個方法exitValue()和waitFor()。往往會發現流的堵塞無法使其得到值就報異常了。這個網上也有解答方法。即要清空getInputStream()和getErrorStream()這兩個流。而且兩個流的清空一定是非同步的。 Java程式碼 收藏程式碼
static void drainInBackground(final InputStream is) {
new Thread(new Runnable(){
public void run(){
try{
while( is.read() >= 0 );
} catch(IOException e){
// return on IOException
}
}
}).start();
}
有沒有好的辦法不寫這個清空流的方法呢!或是還不明白,那就直接用ProcessBuilder來建立Process物件吧!ProcessBuilder已經給出了這方面的解決方案,但是必須要注意的是ProcessBuilder的redirectErrorStream方法。查API可知曉,redirectErrorStream方法設定為ture的時候,會將getInputStream(),getErrorStream()兩個流合併,自動會清空流,無需我們自己處理。如果是false,getInputStream(),getErrorStream()兩個流分開,就必須自己處理,程式如下:
複製程式碼
Java程式碼 收藏程式碼
try {
ProcessBuilder pbuilder=new ProcessBuilder("ping","192.168.0.125");
pbuilder.redirectErrorStream(true);
process=pbuilder.start();
reader=new BufferedReader(new InputStreamReader(process.getInputStream()));
String line=null;
while((line=reader.readLine())!=null){
System.out.println(line);
}
int result=process.waitFor();
System.out.println(result);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
複製程式碼
現在無論你呼叫的是系統自帶命令還是配置環境變數的其他命令,getInputStream()流都能給你過程資訊和執行結果。 如果redirectErrorStream設定為false,那結果會和上面所說一樣。
最後,還要說的是,得到的process.waitFor()結果。別以為這個執行結果值是一層不變的0,API沒有給出具體有多少種型別的返回值,就我測試的結果來看: 0 successfully 1 failure 3 successfully! but a warning ....2沒有測試出來
經過一個上午的不斷測試,找原始碼來看,查資料,終於將這個已經沒有認真理會的API缺陷透徹的梳理了一遍。 為了不重複別的話,很多基礎知識沒有描述,本著重點解決問題和存在的問題。