新聞中心
在編寫Java程序時(shí),有時(shí)候需要在Java程序中執(zhí)行另外一個(gè)程序。

創(chuàng)新互聯(lián)憑借專業(yè)的設(shè)計(jì)團(tuán)隊(duì)扎實(shí)的技術(shù)支持、優(yōu)質(zhì)高效的服務(wù)意識(shí)和豐厚的資源優(yōu)勢(shì),提供專業(yè)的網(wǎng)站策劃、成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、網(wǎng)站優(yōu)化、軟件開發(fā)、網(wǎng)站改版等服務(wù),在成都10多年的網(wǎng)站建設(shè)設(shè)計(jì)經(jīng)驗(yàn),為成都上1000家中小型企業(yè)策劃設(shè)計(jì)了網(wǎng)站。
1、啟動(dòng)程序
Java提供了兩種方法用來啟動(dòng)其它程序:
(1)使用Runtime的exec()方法
(2)使用ProcessBuilder的start()方法
不管在哪種操作系統(tǒng)下,程序具有基本類似的一些屬性。一個(gè)程序啟動(dòng)后就程序操作系統(tǒng)的一個(gè)進(jìn)程,進(jìn)程在執(zhí)行的時(shí)候有自己的環(huán)境變量、有自己的工作目錄。Runtime和ProcessBuilder提供了不同的方式來啟動(dòng)程序,設(shè)置啟動(dòng)參數(shù)、環(huán)境變量和工作目錄。
能夠在Java中執(zhí)行的外部程序,必須是一個(gè)實(shí)際存在的可執(zhí)行文件,對(duì)于shell下的內(nèi)嵌命令是不能直接執(zhí)行的。
采用Runtime的exec執(zhí)行程序時(shí),首先要使用Runtime的靜態(tài)方法得到一個(gè)Runtime,然后調(diào)用Runtime的exec方法??梢詫⒁獔?zhí)行的外部程序和啟動(dòng)參數(shù)、環(huán)境變量、工作目錄作為參數(shù)傳遞給exec方法,該方法執(zhí)行后返回一個(gè)Process代表所執(zhí)行的程序。
Runtime有六個(gè)exec方法,其中兩個(gè)的定義為:
public Process exec(String[] cmdarray, String[] envp, File dir)
public Process exec(String command, String[] envp, File dir)
cmdarray和command為要執(zhí)行的命令,可以將命令和參數(shù)作為一個(gè)字符串command傳遞給exec()方法,也可以將命令和參數(shù)一個(gè)一個(gè)的方在數(shù)組cmdarray里傳遞給exec()方法。
envp為環(huán)境變量,以name=value的形式放在數(shù)組中。dir為工作目錄。
可以不要dir參數(shù),或者不要envp和dir參數(shù),這樣就多出了其它4個(gè)exec()方法。如果沒有dir參數(shù)或者為null,那么新啟動(dòng)的進(jìn)程就繼承當(dāng)前java進(jìn)程的工作目錄。如果沒有envp參數(shù)或者為null,那么新啟動(dòng)的進(jìn)程就繼承當(dāng)前java進(jìn)程的環(huán)境變量。
也可以使用ProcessBuilder類啟動(dòng)一個(gè)新的程序,該類是后來添加到JDK中的,而且被推薦使用。通過構(gòu)造函數(shù)設(shè)置要執(zhí)行的命令以及參數(shù),或者也可以通過command()方法獲取命令信息后在進(jìn)行設(shè)置。通過directory(File directory) 方法設(shè)置工作目錄,通過environment()獲取環(huán)境變量信息來修改環(huán)境變量。
在使用ProcessBuilder構(gòu)造函數(shù)創(chuàng)建一個(gè)新實(shí)例,設(shè)置環(huán)境變量、工作目錄后,可以通過start()方法來啟動(dòng)新程序,與Runtime的exec()方法一樣,該方法返回一個(gè)Process對(duì)象代表啟動(dòng)的程序。
ProcessBuilder與Runtime.exec()方法的不同在于ProcessBuilder提供了redirectErrorStream(boolean redirectErrorStream) 方法,該方法用來將進(jìn)程的錯(cuò)誤輸出重定向到標(biāo)準(zhǔn)輸出里。即可以將錯(cuò)誤輸出都將與標(biāo)準(zhǔn)輸出合并。
2、Process
不管通過那種方法啟動(dòng)進(jìn)程后,都會(huì)返回一個(gè)Process類的實(shí)例代表啟動(dòng)的進(jìn)程,該實(shí)例可用來控制進(jìn)程并獲得相關(guān)信息。Process 類提供了執(zhí)行從進(jìn)程輸入、執(zhí)行輸出到進(jìn)程、等待進(jìn)程完成、檢查進(jìn)程的退出狀態(tài)以及銷毀(殺掉)進(jìn)程的方法:
(1) void destroy()
殺掉子進(jìn)程。
一般情況下,該方法并不能殺掉已經(jīng)啟動(dòng)的進(jìn)程,不用為好。
(2) int exitValue()
返回子進(jìn)程的出口值。
只有啟動(dòng)的進(jìn)程執(zhí)行完成、或者由于異常退出后,exitValue()方法才會(huì)有正常的返回值,否則拋出異常。
(3)InputStream getErrorStream()
獲取子進(jìn)程的錯(cuò)誤流。
如果錯(cuò)誤輸出被重定向,則不能從該流中讀取錯(cuò)誤輸出。
(4)InputStream getInputStream()
獲取子進(jìn)程的輸入流。
可以從該流中讀取進(jìn)程的標(biāo)準(zhǔn)輸出。
(5)OutputStream getOutputStream()
獲取子進(jìn)程的輸出流。
寫入到該流中的數(shù)據(jù)作為進(jìn)程的標(biāo)準(zhǔn)輸入。
(6) int waitFor()
導(dǎo)致當(dāng)前線程等待,如有必要,一直要等到由該 Process 對(duì)象表示的進(jìn)程已經(jīng)終止。
通過該類提供的方法,可以實(shí)現(xiàn)與啟動(dòng)的進(jìn)程之間通信,達(dá)到交互的目的。
3、從標(biāo)準(zhǔn)輸出和錯(cuò)誤輸出流讀取信息
從啟動(dòng)其他程序的Java進(jìn)程看,已啟動(dòng)的其他程序輸出就是一個(gè)普通的輸入流,可以通過getInputStream()和getErrorStream來獲取。
對(duì)于一般輸出文本的進(jìn)程來說,可以將InputStream封裝成BufferedReader,然后就可以一行一行的對(duì)進(jìn)程的標(biāo)準(zhǔn)輸出進(jìn)行處理。
4、舉例
(1)Runtime.exec()
| import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; public class Test1 { //list the files and directorys under C:\ //echo the value of NAME } |
(2)ProcessBuilder
5、獲取進(jìn)程的返回值
通常,一個(gè)程序/進(jìn)程在執(zhí)行結(jié)束后會(huì)向操作系統(tǒng)返回一個(gè)整數(shù)值,0一般代表執(zhí)行成功,非0表示執(zhí)行出現(xiàn)問題。有兩種方式可以用來獲取進(jìn)程的返回值。一是利用waitFor(),該方法是阻塞的,執(zhí)導(dǎo)進(jìn)程執(zhí)行完成后再返回。該方法返回一個(gè)代表進(jìn)程返回值的整數(shù)值。另一個(gè)方法是調(diào)用exitValue()方法,該方法是非阻塞的,調(diào)用立即返回。但是如果進(jìn)程沒有執(zhí)行完成,則拋出異常。
6、阻塞的問題
由Process代表的進(jìn)程在某些平臺(tái)上有時(shí)候并不能很好的工作,特別是在對(duì)代表進(jìn)程的標(biāo)準(zhǔn)輸入流、輸出流和錯(cuò)誤輸出進(jìn)行操作時(shí),如果使用不慎,有可能導(dǎo)致進(jìn)程阻塞,甚至死鎖。
如果將以上事例中的從標(biāo)準(zhǔn)輸出重讀取信息的語句修改為從錯(cuò)誤輸出流中讀取:
那么程序?qū)l(fā)生阻塞,不能執(zhí)行完成,而是hang在那里。
當(dāng)進(jìn)程啟動(dòng)后,就會(huì)打開標(biāo)準(zhǔn)輸出流和錯(cuò)誤輸出流準(zhǔn)備輸出,當(dāng)進(jìn)程結(jié)束時(shí),就會(huì)關(guān)閉他們。在以上例子中,錯(cuò)誤輸出流沒有數(shù)據(jù)要輸出,標(biāo)準(zhǔn)輸出流中有數(shù)據(jù)輸出。由于標(biāo)準(zhǔn)輸出流中的數(shù)據(jù)沒有被讀取,進(jìn)程就不會(huì)結(jié)束,錯(cuò)誤輸出流也就不會(huì)被關(guān)閉,因此在調(diào)用readLine()方法時(shí),整個(gè)程序就會(huì)被阻塞。為了解決這個(gè)問題,可以根據(jù)輸出的實(shí)際先后,先讀取標(biāo)準(zhǔn)輸出流,然后讀取錯(cuò)誤輸出流。
但是,很多時(shí)候不能很明確的知道輸出的先后,特別是要操作標(biāo)準(zhǔn)輸入的時(shí)候,情況就會(huì)更為復(fù)雜。這時(shí)候可以采用線程來對(duì)標(biāo)準(zhǔn)輸出、錯(cuò)誤輸出和標(biāo)準(zhǔn)輸入進(jìn)行分別處理,根據(jù)他們之間在業(yè)務(wù)邏輯上的關(guān)系決定讀取那個(gè)流或者寫入數(shù)據(jù)。
針對(duì)標(biāo)準(zhǔn)輸出流和錯(cuò)誤輸出流所造成的問題,可以使用ProcessBuilder的redirectErrorStream()方法將他們合二為一,這時(shí)候只要讀取標(biāo)準(zhǔn)輸出的數(shù)據(jù)就可以了。
當(dāng)在程序中使用Process的waitFor()方法時(shí),特別是在讀取之前調(diào)用waitFor()方法時(shí),也有可能造成阻塞。可以用線程的方法來解決這個(gè)問題,也可以在讀取數(shù)據(jù)后,調(diào)用waitFor()方法等待程序結(jié)束。
總之,解決阻塞的方法應(yīng)該有兩種:
(1)使用ProcessBuilder類,利用redirectErrorStream方法將標(biāo)準(zhǔn)輸出流和錯(cuò)誤輸出流合二為一,在用start()方法啟動(dòng)進(jìn)程后,先從標(biāo)準(zhǔn)輸出中讀取數(shù)據(jù),然后調(diào)用waitFor()方法等待進(jìn)程結(jié)束。
如:
(2)使用線程
7、在Java中執(zhí)行Java程序
執(zhí)行一個(gè)Java程序的關(guān)鍵在于:
(1)知道JAVA虛擬機(jī)的位置,即java.exe或者java的路徑
(2)知道要執(zhí)行的java程序的位置
(3)知道該程序所依賴的其他類的位置
舉一個(gè)例子,一目了然。
(1)待執(zhí)行的Java類
public class MyTest {
public static void main(String[] args) {
System.out.println("OUTPUT one");
System.out.println("OUTPUT two");
System.err.println("ERROR 1");
System.err.println("ERROR 2");
for(int i = 0; i < args.length; i++)
{
System.out.printf("args[%d] = %s.", i, args[i]);
}
}
}
(2)執(zhí)行該類的程序
| import java.util.*; import java.io.*; class StreamWatch extends Thread { String type; List output = new ArrayList (); boolean debug = false; StreamWatch(InputStream is, String type) { StreamWatch(InputStream is, String type, boolean debug) { public void run() { InputStreamReader isr = new InputStreamReader(is); public List getOutput() { public class Test6 { // process error and output message // start to watch //wait for exit //print the content from ERROR and OUTPUT } catch (Throwable t) { |
【編輯推薦】
- 我們?yōu)槭裁匆獙W(xué)習(xí)Java:Java的八大優(yōu)點(diǎn)
- 淺談Java中使用遞歸方法刪除文件
- JavaFX和Java之間的互操作性
文章標(biāo)題:如何在Java中執(zhí)行其它程序
當(dāng)前URL:http://www.5511xx.com/article/dhioeej.html


咨詢
建站咨詢
