1 問題描寫叙述
Java Web 後端下載下傳了一個經特殊算法壓縮的 zip 檔案,由于不能採用 java 本身自帶的解壓方式,必須採用 7Zip 來解壓。是以,提到了本文中在 java web 後端調用外部 7zip exe 來解壓檔案的問題。
2 主要實作
2.1 定義緩沖區類
class StreamGobbler extends Thread {
InputStream is;
String type;
public StreamGobbler(InputStream is, String type) {
this.is = is;
this.type = type;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line=null;
while ((line = br.readLine()) != null) {
System.out.println(type + ">" + line);
}
} catch (IOException ioe){
ioe.printStackTrace();
}
}
}
2.2 運作外部 exe 流程
String[] cmd = {
"7za.exe",
"x",
zipPath,
"-o" + outputPath
};
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd);
// 監聽出錯資訊
StreamGobbler errorGobbler = new
StreamGobbler(proc.getErrorStream(), "ERROR");
// 監聽輸出資訊
StreamGobbler outputGobbler = new
StreamGobbler(proc.getInputStream(), "OUTPUT");
// 啟動監聽輸入
errorGobbler.start();
outputGobbler.start();
// 確定 Runtime.exec 程序運作完成
int exitVal = proc.waitFor();
System.out.println("ExitValue: " + exitVal);
3 重點解決
3.1 Process.waitFor 在 tomcat 中運作時,卡死狀态
3.1.1 問題原因
一定要在調用Process.waitFor()前将程式的stdout和stderr都讀完,否則就有可能由于pipe的緩沖區不夠,被調用的系統指令堵塞在标準輸出和标準錯誤輸出上。Windows由于這個緩沖區的預設值比較小更easy出現這個問題。
須要注意讀取程式的stdout和stderr都是堵塞的操作,這意味着必須在兩個線程裡分别讀取,而不是在一個線程裡一次讀取,否則還是有可能出現堵塞的情況。
[http://www.dongliu.net/post/496142]
3.1.2 其它推測
1. 程式主程序會等待process一定的時間,可是時間非常少,可能process根本無法完畢工作就結束了。 是以,針對使用較長時間做工作的process,就須要調用waitFor方法。 該方法會引起目前Thread等待,直到process中斷。 [http://ccchhhlll1988-163-com.iteye.com/blog/1901497]
2. 可能是由于在 tomcat 中啟動了一個程序,可是沒有權限來殺死這個程序,是以,一直卡在這個界面
4 其它
4.1 用 Java 自帶的解壓庫
java.util.zip
因為算法不一緻,解壓時提示: “invalid CEN header(bad compression method)”
4.2 下載下傳 7Zip 的解壓庫
在 sourceforge 站點下載下傳 sevenzipjbinding 壓縮包。并且下載下傳的也不是打包好的壓縮檔案
可是因為不支援最新的解壓算法取消。
4.3 tomcat 下是否有調用外部 exe 的權限
4.4 啟動tomcat失敗
server可以正常啟動項目,可是本地電腦不能啟動。提示資訊: "org.apache.catalina.LifecycleException: Failed to start component"
當本地 tomcat6 測試調用外部 exe 成功之後,就考慮在實際項目中測試項目是否成功,實際項目中用的是 tomcat7,同一時候包括了對應的 jdk 目錄,進行了一定的改裝。比方:改動了存放 webapp 的目錄路徑等;删除了一些不必要的檔案等;
發現終于原因是由于: 啟動時使用了本地較低版本号的 jdk,設定 JAVA_HOME 為打包自帶的 jdk 目錄就可以。
5 參考資料
1. runtime.getruntime.exec 中 waitfor 的使用方法
程式設計時,有時候須要在等待調用的系統程式完畢操作後,目前線程才幹做下一步操作,此時能夠用類Process的方法waitFor()來實作,它會堵塞當先線程直至調用程式執行結束。
2. 正确的調用系統指令——為Process.waitFor設定逾時以及其它
是以在代碼中增加逾時控制是必須的。可是Process.waitFor()本身并不支援逾時時間設定,
一個方法是改用非堵塞的Process.exitValue()方法,然後輪詢檢查程序狀态,這樣的方式比較消耗CPU,以至于輪詢間隔也不能設定得太小,總歸不是非常完美。
另外就是另起一個線程來調用程式,在主線程中發現逾時的時候,直接調用process.destroy()終止程序。
3. When Runtime.exec() won't
介紹為什麼不能正常運作 Runtime 函數