Java魔法堂:找外援的利器——Runtime.exec詳解

1、前言                                html

 Java雖然五臟俱全但總有軟肋,譬如獲取CPU等硬件信息,固然咱們能夠經過JNI調用C/C++來獲取,但對於對C/C++和Windows API不熟的碼農是一系列複雜的學習和踩坑過程。那能不能經過簡單一些、學習成本低一些的方式呢?答案是確定的,在功能實現放在首位的狀況下,借他山之石是最簡潔有力的作法。而 Runtime.exec方法 就爲咱們打開這麼的一條路了。java

 

2、認識 java.lang.Runtime.exec方法                     shell

  做用:用於調用外部程序,並重定向外部程序的標準輸入、標準輸出和標準錯誤到緩衝池。功能就是和windows的「運行」同樣啦。windows

  

  方法重載:工具

      exec(String command) ,調用外部程序,入參command爲外部可執行程序的啓動路徑或命令。學習

      exec(String[] cmdArray) ,調用外部程序,入參cmdArray的元素將組合成爲一條完整的外部可執行程序的啓動路徑或命令。spa

      exec(String command, String[] envp) ,在調用外部程序以前設置系統環境變量,該變量僅供command入參使用,envp每一個元素爲一個系統環境變量,而且字符串格式爲「環境變量名=環境變量值」。命令行

       exec(String command, String[] envp, File dir) , 除了設置系統環境變量外,還經過入參dir設置當前工做目錄。線程

  實例 —— 在當前目錄執行dir命令,並將結果保存到c:\dir.txt文本文件中:code

  前提:假設當前用戶的家目錄爲c:\user\fsjohnhuang

  c:\user\fsjohnhuang下的目錄結構

c:\user\fsjohnhuang 
|--jottings 
|--test.txt

  d:\test下的目錄結構

d:\test
|--movies
|--readme.txt

  代碼片斷

Runtime r = Runtime.getRuntime();
try{
  Process proc = r.exec("cmd /c dir > %dest%", new String[]{"dest=c:\\dir.txt", new File("d:\\test")});
  int exitVal = proc.waitFor(); // 阻塞當前線程,並等待外部程序停止後獲取結果碼
  System.out.println(exitVal == 0 ? "成功" : "失敗");
}
catch(Exception e){
  e.printStackTrace();
}

  執行代碼後查看c:\dir.txt文件內容如以下:

驅動器 D 中的卷沒有標籤。
 卷的序列號是 8074-B214

 D:\test 的目錄

2014/09/22  14:45    <DIR>          movies
2014/03/31  17:14             8,642 readme.txt

 

3、注意點                              

  1.  Runtime.exec() 不是cmd或shell環境,所以沒法直接調用dir等命令。若要調用命令行下的命令,請參考第2節的實例。

  2.  經過 Process實例.getInputStream() 和 Process實例.getErrorStream() 獲取的輸入流和錯誤信息流是緩衝池向當前Java程序提供的,而不是直接獲取外部程序的標準輸出流和標準錯誤流。

  

   而緩衝池的容量是必定的,所以若外部程序在運行過程當中不斷向緩衝池輸出內容,當緩衝池填滿,那麼外部程序將暫停運行直到緩衝池有空位可接收外部程序的輸出內容爲止。(採用xcopy命令複製大量文件時將會出現該問題)

   解決辦法就是當前的Java程序不斷讀取緩衝池的內容,從而爲騰出緩衝池的空間。

 

4、絕對是坑                              

  爲解決第3節第2點注意事項中說起的問題。咱們能夠經過下列兩種方式處理

Runtime r = Runtime.getRuntime();
try{
  Process proc = r.exec("cmd /c dir"); // 假設該操做爲形成大量內容輸出
  // 採用字符流讀取緩衝池內容,騰出空間
  BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream(), "gbk")));
  String line = null;
  while ((line = reader.readLine()) != null){
     System.out.println(line);
  }

  // 或採用字節流讀取緩衝池內容,騰出空間
  // ByteArrayOutputStream pool = new ByteArrayOutputStream();
  // byte[] buffer = new byte[1024];
  // int count = -1;
  // while ((count = proc.getInputStream().read(buffer)) != -1){
  //   pool.write(buffer, 0, count);
  //   buffer = new byte[1024];
  // }
  // System.out.println(pool.toString("gbk"));

  int exitVal = proc.waitFor();
  System.out.println(exitVal == 0 ? "成功" : "失敗");
}
catch(Exception e){
  e.printStackTrace();
}

這裏要注意一個坑:外部程序在執行結束後將會自動關閉,不然無論是字符流仍是字節流均因爲既讀不到數據,又讀不到流結束符而出現阻塞Java進程運行的狀況。

而 cmd /c 就是告訴cmd環境進程,當執行完成後關閉自身。

 

5、總結                                  

  用適當的工具作適當的事, Runtime.exec方法 讓咱們功能實現的手段更靈活了!

  尊重原創,轉載請註明來自:http://www.cnblogs.com/fsjohnhuang/p/4081445.html  ^_^肥仔John

 

6、參考                                  

  http://fuliang.iteye.com/blog/574260

相關文章
相關標籤/搜索