java調用process 有兩種實現方法,一是使用Runtime類,二是使用Process類。
我在最近的項目里用的是Runtime類,接下來寫下總結。
有圖有真相(在網上學來一句話)
1 package com.lee.demo; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 8 public class RuntimeDemo01 { 9 10 public static void main(String[] args) { 11 String s; 12 StringBuilder sb = new StringBuilder(); 13 InputStream fis = null; 14 try { 15 // Process process = Runtime.getRuntime().exec("ping localhost");
Process process = Runtime.getRuntime().exec(new String[]{"sh", "-c", XXXX});
// 注意,我將原來的15行注釋掉了,變成了下面的寫法。聲明,我調用的command是Lunix下的命令,如果你用的是windows的話,不需要這么寫。
// 為什么要使用這樣的寫法,因為項目需要考慮到單引號雙引號等,轉換加/的原因。 16 fis = process.getInputStream(); 17 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fis)); 18 while((s=bufferedReader.readLine()) != null) { 19 sb.append(s);
//sb.append(\n); 20 } 21 System.out.println(sb.toString()); 22 process.waitFor(); 23 System.out.println(process.exitValue()); 24 } catch (InterruptedException e) { 25 e.printStackTrace(); 26 } catch (IOException e) { 27 e.printStackTrace(); 28 } finally { 29 try { 30 fis.close(); 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } 34 } 35 } 36 }
執行結果如下
使用法: ping [-t] [-a] [-n 要求數] [-l サイズ] [-f] [-i TTL] [-v TOS] [-r ホップ數] [-s ホップ數] [[-j ホスト一覧] | [-k ホスト一覧]] [-w タイムアウト] [-R] [-S ソースアドレス] [-4] [-6] ターゲット名オプション: -t 中斷されるまで、指定されたホストを Ping します。 統計を表示して続行するには、Ctrl+Break を押してください。 停止するには、Ctrl+C を押してください。 -a アドレスをホスト名に解決します。 -n 要求數 送信するエコー要求の數です。 -l サイズ 送信バッファーのサイズです。 -f パケット內の Don't Fragment フラグを設定します (IPv4 のみ)。 -i TTL Time To Live です。 -v TOS Type Of Service (IPv4 のみ。この設定はもう使用されておらず、 IP ヘッダー內のサービス フィールドの種類に影響しません)。 -r ホップ數 指定したホップ數のルートを記録します (IPv4 のみ)。 -s ホップ數 指定したホップ數のタイムスタンプを表示します (IPv4 のみ)。 -j ホスト一覧 一覧で指定された緩やかなソース ルートを使用します (IPv4 のみ)。 -k ホスト一覧 一覧で指定された厳密なソース ルートを使用します (IPv4 のみ)。 -w タイムアウト 応答を待つタイムアウトの時間 (ミリ秒) です。 -R ルーティング ヘッダーを使用して逆ルートもテストします (IPv6 のみ)。 -S ソースアドレス 使用するソース アドレスです。 -4 IPv4 の使用を強制します。 -6 IPv6 の使用を強制します。
如果你執行的命令是 ping localhost的話,那么是可以正常執行並返回黑屏下一樣的結果的。
在這里說一下我遇到的幾個坑。
首先,lunix下執行和windows下執行不一樣。比如上面的例子中,ping這個命令,沒有添加參數時,在執行結果中會打出黑屏下一樣的提示信息,但是lunix下不行,在程序中需要process.getErrorStream(),這樣才能得到一致的結果。
第二個坑,是要記得添加process.waitFor();這行代碼,代碼的意思是 線程一直到process結束再往下執行。如果不寫這行代碼,那么process執行的同時,線程在往下執行,到后面23行的代碼會拋出error。此外,process.waitFor()代碼要放在,對輸入流的操作之后,因為每次輸入流讀取的大小是有限制的,如果超過最大值,而輸入流中的內容沒有被讀取,那么久會發生阻塞,到時程序一直停在那里。
第三個坑,在上文中代碼的第17行里,使用了匿名類的new InputStreamReader,在性能測試的時候,報錯,can not open too many files,原因是InputStreamReader使用了之后,最后沒有將他close。一定要在finally中將它close掉。
第四個坑,代碼第18行,readLine()方法,大家很熟悉。我們看一下API中的定義。
public String readLine()
throws IOException
Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.
Returns:
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
Throws:
IOException - If an I/O error occurs
在returns中,明確寫明,只返回內容,不會返回換行符號等。這就導致最后我們取得的內容是一行String,很長。我決定在19行后,加個換行符,這樣就可以換行了。
接下來,簡單說明一下Process類,要說的是,自jdk1.5起,官方建議,使用ProcessBuilder.start()來啟動process
官方文檔地址: https://docs.oracle.com/javase/8/docs/api/java/lang/Process.html
其實JDK中Runtime最終調用的是processbuilder。
processbuilder提供的功能更加豐富,可以設置工作目錄,環境變量等。
推薦一篇文章,processBuilder介紹得很好。
http://www.cnblogs.com/taven/archive/2011/12/17/2291460.html
