Java 執行系統命令


在Java中執行系統命令,主要是使用ProcessBuilder和Runtime.getRuntime().exec()。而在這里主要是介紹兩種方法的使用。
使用情景是在linux系統中,使用mencoder來進行視頻轉碼。將視頻轉為flv格式,因為轉為flv格式命令較為簡單,如要轉為MP4格式,可以看官方文檔介紹

一.使用Runtime

##上傳之后的視頻文件名為test.tmpmedia
String command = "mencoder test.tmpmedia -o test.flv -ofps 25 -of lavf -oac mp3lame -srate 22050 -ovc lavc -lavcopts "
                + "vcodec=flv:keyint=59:vbitrate=6000:mbd=2:trell:v4mv:o=mpv_flagg=cbp_rd:last_pred=3 -vf harddup,scale=480:256";

Process p = Runtime.getRuntime().exec(command);

##讀取命令的輸出信息
InputStream is = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
p.waitFor();
if (p.exitValue() != 0) {
    //說明命令執行失敗
    //可以進入到錯誤處理步驟中
}

##打印輸出信息
String s = null;
while ((s = reader.readLine()) != null) {
    System.out.println(s);
}

其中waitFor()方法會阻塞當前進程,直到命令執行結束。而exitValue不會阻塞進程,但是調用exitValue的時候,如果命令沒有執行完成就會報錯,感覺這樣設計挺奇怪的。
所以,想要獲取到命令是否執行成功,就搭配waitForexitValue

使用Runtime執行命令感覺是比較方便的,直接可以將命令寫入exec()中。如果僅僅是這樣寫的話,轉碼是會一直卡死在那里的。而你將命令直接放到終端中執行,又不會出現問題。
原因就在轉碼時候,會輸出大量的信息(標准輸出和標准錯誤),如果不清理java的緩存區,就會導致緩存區滿而命令無法繼續執行的情況。
那么解決辦法肯定就是清理緩存區,而使用Runtime清理的話,你至少得再開另外一個線程,才能同時getInputStreamgetErrorStream,這樣並不是我喜歡的,所以便采用了ProcessBuilder

二.使用ProcessBuilder

#將命令分解為List存儲
String[] commandSplit = command.split(" ");
List<String> lcommand = new ArrayList<String>();
for (int i = 0; i < commandSplit.length; i++) {
	lcommand.add(commandSplit[i]);
}

ProcessBuilder processBuilder = new ProcessBuilder(lcommand);
processBuilder.redirectErrorStream(true);
Process p = processBuilder.start();
InputStream is = p.getInputStream();
BufferedReader bs = new BufferedReader(new InputStreamReader(is));

p.waitFor();
if (p.exitValue() != 0) {
    //說明命令執行失敗
    //可以進入到錯誤處理步驟中
}
String line = null;
while ((line = bs.readLine()) != null) {
	System.out.println(line);
	resultLog += line;
}

ProcessBuilder可以使用redirectErrorStream將標准輸出和標准錯誤流合並,然后使用getInputStream獲取到流,放入BufferedReader中打印出來,便可解決緩存區滿的問題
唯一感覺不太方便就是命令執行已List<String>或者String []的形式傳入。

上面的兩種方法都是以阻塞的方式執行命令的,要想在后台執行命令,並且命令執行成功后通知,失敗后記錄日志,那就只能在主線程中開一個線程,專門用來轉碼。可以參考下一篇文章《
Spring中多線程轉碼,bean的注入問題》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM