日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java Process中waitFor()的问题

發布時間:2023/12/2 java 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java Process中waitFor()的问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java Process中waitFor()的問題

http://yearsaaaa123789.iteye.com/blog/1404865

? ? ? ? ??在編寫Java程序時,有時候我們需要調用其他的諸如exe,shell這樣的程序或腳本。在Java中提供了兩種方法來啟動其他程序:(1) 使用Runtime的exec()方法(2) 使用ProcessBuilder的start()方法 。Runtime和ProcessBulider提供了不同的方式來啟動程序,設置啟動參數、環境變量和工作目錄。但是這兩種方法都會返回一個用于管理操作系統進程的Process對象。這個對象中的waitFor()是我們今天要討論的重點。

? ? ? 來說說我遇到的實際情況:我想調用ffmpeg程序來對一首歌曲進行轉碼,把高音質版本的歌曲轉為多種低碼率的文件。但是在轉碼完成之后需要做以下操作:讀取文件大小,寫入ID3信息等。這時我們就想等轉碼操作完成之后我們可以知道。

如下這樣代碼

?

Java代碼 ?
  • Process?p?=?null;??
  • try?{??
  • ????p?=?Runtime.getRuntime().exec("notepad.exe");??
  • }?catch?(Exception?e)?{??
  • ????e.printStackTrace();??
  • }??
  • System.out.println("我想被打印...");??
  • ?在notepad.exe被執行的同時,打印也發生了,但是我們想要的是任務完成之后它才被打印。


    之后發現在Process類中有一個waitFor()方法可以實現。如下:

    ?

    Java代碼 ?
  • Process?p?=?null;??
  • try?{??
  • ????p?=?Runtime.getRuntime().exec("notepad.exe");??
  • ????p.waitFor();??
  • }?catch?(Exception?e)?{??
  • ????e.printStackTrace();??
  • }??
  • System.out.println("我想被打印...");??
  • ?這下又出現了這樣的現象,必須要等我們把記事本關閉打印語句才會被執行。并且你不碰手動關閉它那程序就一直不動,程序貌似掛了.....這是什么情況,想調用個別的程序有這么難嗎?讓我們來看看waitFor()的說明:


    JDK幫助文檔上這么說:如有必要,一直要等到由該 Process 對象表示的進程已經終止。如果已終止該子進程,此方法立即返回。但是直接調用這個方法會導致當前線程阻塞,直到退出子進程。對此JDK文檔上還有如此解釋:因為本地的系統對標準輸入和輸出所提供的緩沖池有效,所以錯誤的對標準輸出快速的寫入何從標準輸入快速的讀入都有可能造成子進程的所,甚至死鎖。好了,問題的關鍵在緩沖區這個地方:可執行程序的標準輸出比較多,而運行窗口的標準緩沖區不夠大,所以發生阻塞。接著來分析緩沖區,哪來的這個東西,當Runtime對象調用exec(cmd)后,JVM會啟動一個子進程,該進程會與JVM進程建立三個管道連接:標準輸入,標準輸出和標準錯誤流。假設該程序不斷在向標準輸出流和標準錯誤流寫數據,而JVM不讀取的話,當緩沖區滿之后將無法繼續寫入數據,最終造成阻塞在waitfor()這里。 知道問題所在,我們解決問題就好辦了。查看網上說的方法多數是開兩個線程在waitfor()命令之前讀出窗口的標準輸出緩沖區和標準錯誤流的內容。代碼如下:

    ?

    Java代碼 ?
  • Runtime?rt?=?Runtime.getRuntime();??
  • String?command?=?"cmd?/c?ffmpeg?-loglevel?quiet?-i?"+srcpath+"?-ab?"+bitrate+"k?-acodec?libmp3lame?"+desfile;??
  • try?{??
  • ?p?=?rt.exec(command?,null,new?File("C:\\ffmpeg-git-670229e-win32-static\\bin"));??
  • ?//獲取進程的標準輸入流??
  • ?final?InputStream?is1?=?p.getInputStream();???
  • ?//獲取進城的錯誤流??
  • ?final?InputStream?is2?=?p.getErrorStream();??
  • ?//啟動兩個線程,一個線程負責讀標準輸出流,另一個負責讀標準錯誤流??
  • ?new?Thread()?{??
  • ????public?void?run()?{??
  • ???????BufferedReader?br1?=?new?BufferedReader(new?InputStreamReader(is1));??
  • ????????try?{??
  • ????????????String?line1?=?null;??
  • ????????????while?((line1?=?br1.readLine())?!=?null)?{??
  • ??????????????????if?(line1?!=?null){}??
  • ??????????????}??
  • ????????}?catch?(IOException?e)?{??
  • ?????????????e.printStackTrace();??
  • ????????}??
  • ????????finally{??
  • ?????????????try?{??
  • ???????????????is1.close();??
  • ?????????????}?catch?(IOException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ??????????}??
  • ????????}??
  • ?????}.start();??
  • ????????????????????????????????
  • ???new?Thread()?{???
  • ??????public?void??run()?{???
  • ???????BufferedReader?br2?=?new??BufferedReader(new??InputStreamReader(is2));???
  • ??????????try?{???
  • ?????????????String?line2?=?null?;???
  • ?????????????while?((line2?=?br2.readLine())?!=??null?)?{???
  • ??????????????????if?(line2?!=?null){}??
  • ?????????????}???
  • ???????????}?catch?(IOException?e)?{???
  • ?????????????????e.printStackTrace();??
  • ???????????}???
  • ??????????finally{??
  • ?????????????try?{??
  • ?????????????????is2.close();??
  • ?????????????}?catch?(IOException?e)?{??
  • ?????????????????e.printStackTrace();??
  • ?????????????}??
  • ???????????}??
  • ????????}???
  • ??????}.start();????
  • ????????????????????????????????
  • ??????p.waitFor();??
  • ??????p.destroy();???
  • ?????System.out.println("我想被打印...");??
  • ????}?catch?(Exception?e)?{??
  • ????????????try{??
  • ????????????????p.getErrorStream().close();??
  • ????????????????p.getInputStream().close();??
  • ????????????????p.getOutputStream().close();??
  • ????????????????}??
  • ?????????????catch(Exception?ee){}??
  • ??????????}??
  • ???}??
  • ?這個方法確實可以解決調用waitFor()方法阻塞無法返回的問題。但是在其中過程中我卻發現真正起關鍵作用的緩沖區是getErrorStream()說對應的那個緩沖區沒有被清空,意思就是說其實只要及時讀取標準錯誤流緩沖區的數據程序就不會被block。

    ?

    Java代碼 ?
  • StringBuffer?sb?=?new?StringBuffer();??
  • try?{??
  • Process?pro?=?Runtime.getRuntime().exec(cmdString);??
  • BufferedReader?br?=?new?BufferedReader(new?InputStreamReader(pro.getInputStream()),?4096);??
  • String?line?=?null;??
  • int?i?=?0;??
  • while?((line?=?br.readLine())?!=?null)?{??
  • if?(0?!=?i)??
  • sb.append("\r\n");??
  • i++;??
  • sb.append(line);??
  • }??
  • }?catch?(Exception?e)?{??
  • sb.append(e.getMessage());??
  • }??
  • return?sb.toString();??
  • ?

    ?不過這種寫法不知道是不是適合所有的情況,網上其他人說的需要開兩個線程可能不是沒有道理。這個還是具體問題具體對待吧。

    ?

    到這里問題的原因也清楚了,問題也被解決了,是不是就結束了。讓我們回過頭來再分析一下,問題的關鍵是處在輸入流緩沖區那個地方,子進程的產生的輸出流沒有被JVM及時的讀取最后緩沖區滿了就卡住了。如果我們能夠不讓子進程向輸入流寫入數據,是不是可以解決這個問題。對于這個想法直接去ffmpeg官網查找,最終發現真的可以關閉子進程向窗口寫入數據。命令如下: ffmpeg.exe -loglevel quiet -i 1.mp3 -ab 16k -ar 22050 -acodec libmp3lame r.mp3 稍微分析一下-acodec?音頻流編碼方式?-ab 音頻流碼率(默認是同源文件碼率,也需要視codec而定) -ar?音頻流采樣率(大多數情況下使用4410048000,分別對應PAL制式和NTSC制式,根據需要選擇),重點就是-loglevel quiet這句? http://www.ffmpeg.com.cn/index.php/Ffmpeg%E9%80%89%E9%A1%B9%E8%AF%A6%E8%A7%A3

    ?

    這才是我們想要的結果:

    ?

    Java代碼 ?
  • try?{??
  • ??p?=?Runtime.getRuntime().exec("cmd?/c?ffmpeg?-loglevel?quiet?-i?????D:\\a.mp3?-ab?168k?-ar?22050?-acodec?libmp3lame?D:\\b.mp3",null,??
  • ????????????????????new?File(?"C:\\ffmpeg-git-670229e-win32-static\\bin"));??
  • ??p.waitFor();??
  • }?catch?(Exception?e)?{??
  • ????e.printStackTrace();??
  • }??
  • System.out.println("我想被打印...");??
  • ?

    最后是自己寫的一個簡單的操作MP3文件的類

    ?

    Java代碼 ?
  • package?com.yearsaaaa.util;??
  • ??
  • import?java.io.File;??
  • import?java.io.FileInputStream;??
  • import?java.math.BigDecimal;??
  • ??
  • import?javazoom.jl.decoder.Bitstream;??
  • import?javazoom.jl.decoder.Header;??
  • ??
  • /**?
  • ?*?@className:MP3Util.java?
  • ?*?@classDescription:?
  • ?*?@author:MChen?
  • ?*?@createTime:2012-2-9?
  • ?*/??
  • public?class?MP3Util?{??
  • ??????
  • ????/**?
  • ?????*?獲取文件大小,以M為單位,保留小數點兩位?
  • ?????*/??
  • ????public?static?double?getMP3Size(String?path)??
  • ????{??
  • ????????File?file?=?new?File(path);??
  • ????????double?size?=?(double)file.length()/(1024*1024);??
  • ????????size?=?new?BigDecimal(size).setScale(2,BigDecimal.ROUND_UP).doubleValue();??
  • ????????System.out.println("MP3文件的大小為:"+size);??
  • ????????return?size;??
  • ????}??
  • ??????
  • ????/**?
  • ?????*?該方法只能獲取mp3格式的歌曲長度?
  • ?????*?庫地址:http://www.javazoom.net/javalayer/javalayer.html?
  • ?????*/??
  • ????public?static?String?getMP3Time(String?path)??
  • ????{??
  • ????????String?songTime?=?null;??
  • ????????FileInputStream?fis?=?null;??
  • ????????Bitstream?bt?=?null;??
  • ????????File?file?=?new?File(path);??
  • ????????try?{??
  • ????????????fis?=?new?FileInputStream(file);??
  • ????????????int?b=fis.available();??
  • ????????????bt=new?Bitstream(fis);??
  • ????????????Header?h=bt.readFrame();??
  • ????????????int?time=(int)?h.total_ms(b);??
  • ????????????int?i=time/1000;??
  • ????????????bt.close();??
  • ????????????fis.close();??
  • ????????????if(i%60?==?0)??
  • ????????????????songTime?=?(i/60+":"+i%60+"0");??
  • ????????????if(i%60?<10)??
  • ????????????????songTime?=?(i/60+":"+"0"+i%60);??
  • ????????????else??
  • ????????????????songTime?=?(i/60+":"+i%60);??
  • ????????????System.out.println("該歌曲的長度為:"+songTime);??
  • ????????}??
  • ????????catch?(Exception?e)?{??
  • ????????????try?{??
  • ????????????????bt.close();??
  • ????????????????fis.close();??
  • ????????????}?catch?(Exception?ee)?{??
  • ????????????????ee.printStackTrace();??
  • ????????????}??
  • ????????}??
  • ????????return?songTime;??
  • ????}??
  • ??????
  • ????/**?
  • ?????*?將源MP3向下轉碼成低品質的文件?
  • ?????*?@參數:?@param?srcPath?源地址?
  • ?????*?@參數:?@param?bitrate?比特率?
  • ?????*?@參數:?@param?desfile?目標文件?
  • ?????*?@return?void????
  • ?????*?@throws?
  • ?????*/??
  • ????public?static?void?mp3Transcoding(String?srcPath,String?bitrate,String?desFile)??
  • ????{?????
  • ????????//Java調用CMD命令時,不能有空格??
  • ????????String?srcpath?=?srcPath.replace("?",?"\"?\"");??
  • ????????String?desfile?=?desFile.replace("?",?"\"?\"");??
  • ????????Runtime?rt?=?Runtime.getRuntime();??
  • ????????String?command?=?"cmd?/c?ffmpeg?-loglevel?quiet?-i?"+srcpath+"?-ab?"+bitrate+"k?-acodec?libmp3lame?"+desfile;??
  • ????????System.out.println(command);??
  • ????????Process?p?=?null;??
  • ????????try{??
  • ????????????//在Linux下調用是其他寫法??
  • ????????????p?=?rt.exec(command?,null,new?File("C:\\ffmpeg-git-670229e-win32-static\\bin"));??
  • ????????????p.waitFor();??
  • ????????????System.out.println("線程返回,轉碼后的文件大小為:"+desFile.length()+",現在可以做其他操作了,比如重新寫入ID3信息。");??
  • ????????}??
  • ????????catch(Exception?e){??
  • ????????????e.printStackTrace();??
  • ????????????try{??
  • ????????????????p.getErrorStream().close();??
  • ????????????????p.getInputStream().close();??
  • ????????????????p.getOutputStream().close();??
  • ????????????????}??
  • ????????????catch(Exception?ee){}??
  • ????????}??
  • ????}??
  • ??????
  • ????public?static?void?main(String[]?args)?{??
  • ????????//String[]?str?=?{"E:\\Kugou\\陳慧嫻?-?不羈戀人.mp3","E:\\Kugou\\三寸天堂.mp3","E:\\Tmp\\陳淑樺?-?夢醒時分.mp3","E:\\Tmp\\1.mp3","E:\\Test1\\走天涯、老貓?-?楊望.acc","E:\\Test1\\因為愛情?鈴.mp3"};??
  • ????????String[]?str?=?{"E:\\Kugou\\三寸天堂.mp3"};??
  • ????????for(String?s?:?str)??
  • ????????{??
  • ????????????//getMP3Size(s);??
  • ????????????//getMP3Time(s);??
  • ????????????File?f?=?new?File(s);??
  • ????????????mp3Transcoding(f.getAbsolutePath(),"64","d:\\chenmiao.mp3");??
  • ????????}??
  • ????}??
  • }

  • 總結

    以上是生活随笔為你收集整理的Java Process中waitFor()的问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。