Java - Use Java Runtime to execute 7za.exe compress and extract commands

之前曾經有使用過Java來執行外部執行檔(如:.exe),進而產生出所需要的結果檔案。

而在這邊主要是使用7za.exe執行檔來進行壓縮及解壓縮的動作,紀錄一下如果使用7za.exe

需要搭配什麼樣的指令才可以達到基本壓縮及解壓縮的動作,而也會討論到使用Process時

需要注意的一些事情。

基本上在使用Java來執行外部執行檔時,需要另外定義一process,相對主程式而言為

subprocess。process需要透過Runtime.getRuntime().exec(command)來產生實體,當下也已經

做執行的動作了。

而process本身有下列幾項的函式可以使用,如exitValue,可以得到執行結果,印出0表示正

常的終止;waitFor,表示主程式需等待subprocess執行完成,並回傳如exitValue的執行結果,

才會終止結束程式,但是如果subprocess執行的當下發生錯誤,會hang住主程式,導致無法

繼續正常運作。


在此,範例程式如下:
  1. public static void main(String[] args) {
  2. // TODO Auto-generated method stub
  3. String root = "C:\\Java program\\Java Zip";
  4. String tmpFolderPath = root+"\\dirs\\*.txt";
  5. String zipPath = "tools\\7za920";
  6. SimpleDateFormat date_convert = new SimpleDateFormat("yyyyMMddHHmmss");
  7. String report_dname = date_convert.format(new java.sql.Date(System.currentTimeMillis()));
  8. String outFolderPath = "output\\"+report_dname+".7z";
  9. String zip_exe[]={zipPath + "\\7za.exe","a","-t7z",outFolderPath,tmpFolderPath};
  10. System.out.println("壓縮執行結果-Process exitValue: " + execCommand(zip_exe));
  11. zip_exe=new String[]{zipPath + "\\7za.exe","x",outFolderPath, "-o"+root+"\\output\\"+report_dname};
  12. System.out.println("解壓縮執行結果-Process exitValue: " + execCommand(zip_exe));
  13. }
  14. public static int execCommand(String zip_exe[]){
  15. Process p = null;
  16. InputStream in_b = null;
  17. BufferedReader reader = null;
  18. int exitVal = 0;
  19. try{
  20. p = Runtime.getRuntime().exec(zip_exe);
  21. //in_b = p.getInputStream();
  22. //reader = new BufferedReader(new InputStreamReader(in_b));
  23. String str = null;
  24. System.out.println("<output>");
  25. // while ((str = reader.readLine()) != null){
  26. // System.out.println(str);
  27. // }
  28. System.out.println("</output>");
  29. exitVal = p.exitValue();
  30. }/*catch(InterruptedException e){
  31. e.printStackTrace();
  32. }*/catch(IOException e){
  33. e.printStackTrace();
  34. }finally{
  35. p.destroy();
  36. // try {
  37. // in_b.close();
  38. // reader.close();
  39. // } catch (IOException e) {
  40. // // TODO Auto-generated catch block
  41. // e.printStackTrace();
  42. // }
  43. }
  44. return exitVal;
  45. }

在這邊宣告zip_exe array,組成執行壓縮及解壓縮的指令

執行壓縮

參數1: 7za.exe的執行檔絕對路徑

參數2: a => 壓縮指令

參數3: -t7z 壓縮方式

參數4: 輸出壓縮檔的路徑

參數5: 檔案的來源路徑

ps. 假設參數5所帶入為相對路徑,檔案在壓縮的當下會將存放檔案的目錄一起壓縮進去,

填入絕對路徑的話,則壓縮檔內只有檔案本身!

解壓縮

參數1: 7za.exe的執行檔絕對路徑

參數2: x => 解壓縮指令

參數3: 壓縮檔案的來源路徑

參數4: -oC:\\目錄名稱

ps. 參數4 -o後的路徑為解壓縮後檔案存放的地方,若目錄不存在的話會自動建立!

當下的執行結果如下:


撇開註解掉的程式碼,當下如果執行的話,會出現錯誤!

主要訊息為 java.lang.IllegalThreadStateException: process has not exited

表示subprocess在還沒有執行完的當下,主程式就已經結束了,導致subprocess被不正常的

強制結束!!

此時將31行的程式改成 => exitVal = p.waitFor();

並且32 ~ 34行的InterruptedException catch註解也拿掉!

此時執行結果如下:


由上面曾經提到的waitFor功用,使得subprocess所執行的壓縮及解壓縮可以順利完成!


而我們還是決定改回exitValue,而程式又要順利執行,程式碼可以修改如下:

  1. try{
  2. p = Runtime.getRuntime().exec(zip_exe);
  3. in_b = p.getInputStream();
  4. reader = new BufferedReader(new InputStreamReader(in_b));
  5. String str = null;
  6. System.out.println("<output>");
  7. while ((str = reader.readLine()) != null){
  8. System.out.println(str);
  9. }
  10. System.out.println("</output>");
  11. exitVal = p.exitValue();
  12. }/*catch(InterruptedException e){
  13. e.printStackTrace();
  14. }*/catch(IOException e){
  15. e.printStackTrace();
  16. }finally{
  17. p.destroy();
  18. try {
  19. in_b.close();
  20. reader.close();
  21. } catch (IOException e) {
  22. // TODO Auto-generated catch block
  23. e.printStackTrace();
  24. }
  25. }

在此將讀取Process在執行7za.exe過程之中執行指令的InputStream資料,並且將此過程列印

出來,這個目的主要也代表了主程式當下也在等待subprocess的執行過程,如此一來可能不

會自行先結束!

留言