您好,登錄后才能下訂單哦!
本篇文章為大家展示了Java中怎么執(zhí)行其它程序,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。
1、啟動(dòng)程序
Java提供了兩種方法用來(lái)啟動(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提供了不同的方式來(lái)啟動(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()方法。如果沒(méi)有dir參數(shù)或者為null,那么新啟動(dòng)的進(jìn)程就繼承當(dāng)前java進(jìn)程的工作目錄。如果沒(méi)有envp參數(shù)或者為null,那么新啟動(dòng)的進(jìn)程就繼承當(dāng)前java進(jìn)程的環(huán)境變量。
也可以使用ProcessBuilder類啟動(dòng)一個(gè)新的程序,該類是后來(lái)添加到JDK中的,而且被推薦使用。通過(guò)構(gòu)造函數(shù)設(shè)置要執(zhí)行的命令以及參數(shù),或者也可以通過(guò)command()方法獲取命令信息后在進(jìn)行設(shè)置。通過(guò)directory(File directory) 方法設(shè)置工作目錄,通過(guò)environment()獲取環(huán)境變量信息來(lái)修改環(huán)境變量。
在使用ProcessBuilder構(gòu)造函數(shù)創(chuàng)建一個(gè)新實(shí)例,設(shè)置環(huán)境變量、工作目錄后,可以通過(guò)start()方法來(lái)啟動(dòng)新程序,與Runtime的exec()方法一樣,該方法返回一個(gè)Process對(duì)象代表啟動(dòng)的程序。
ProcessBuilder與Runtime.exec()方法的不同在于ProcessBuilder提供了redirectErrorStream(boolean redirectErrorStream) 方法,該方法用來(lái)將進(jìn)程的錯(cuò)誤輸出重定向到標(biāo)準(zhǔn)輸出里。即可以將錯(cuò)誤輸出都將與標(biāo)準(zhǔn)輸出合并。
2、Process
不管通過(guò)那種方法啟動(dòng)進(jìn)程后,都會(huì)返回一個(gè)Process類的實(shí)例代表啟動(dòng)的進(jìn)程,該實(shí)例可用來(lái)控制進(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)程的輸出流。
寫(xiě)入到該流中的數(shù)據(jù)作為進(jìn)程的標(biāo)準(zhǔn)輸入。
(6) int waitFor()
導(dǎo)致當(dāng)前線程等待,如有必要,一直要等到由該 Process 對(duì)象表示的進(jìn)程已經(jīng)終止。
通過(guò)該類提供的方法,可以實(shí)現(xiàn)與啟動(dòng)的進(jìn)程之間通信,達(dá)到交互的目的。
3、從標(biāo)準(zhǔn)輸出和錯(cuò)誤輸出流讀取信息
從啟動(dòng)其他程序的Java進(jìn)程看,已啟動(dòng)的其他程序輸出就是一個(gè)普通的輸入流,可以通過(guò)getInputStream()和getErrorStream來(lái)獲取。
對(duì)于一般輸出文本的進(jìn)程來(lái)說(shuō),可以將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
import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; |
5、獲取進(jìn)程的返回值
通常,一個(gè)程序/進(jìn)程在執(zhí)行結(jié)束后會(huì)向操作系統(tǒng)返回一個(gè)整數(shù)值,0一般代表執(zhí)行成功,非0表示執(zhí)行出現(xiàn)問(wèn)題。有兩種方式可以用來(lái)獲取進(jìn)程的返回值。一是利用waitFor(),該方法是阻塞的,執(zhí)導(dǎo)進(jìn)程執(zhí)行完成后再返回。該方法返回一個(gè)代表進(jìn)程返回值的整數(shù)值。另一個(gè)方法是調(diào)用exitValue()方法,該方法是非阻塞的,調(diào)用立即返回。但是如果進(jìn)程沒(méi)有執(zhí)行完成,則拋出異常。
6、阻塞的問(wèn)題
由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)輸出重讀取信息的語(yǔ)句修改為從錯(cuò)誤輸出流中讀取:
stdout = new BufferedReader(new InputStreamReader(p .getErrorStream())); |
那么程序?qū)l(fā)生阻塞,不能執(zhí)行完成,而是hang在那里。
當(dāng)進(jìn)程啟動(dòng)后,就會(huì)打開(kāi)標(biāo)準(zhǔn)輸出流和錯(cuò)誤輸出流準(zhǔn)備輸出,當(dāng)進(jìn)程結(jié)束時(shí),就會(huì)關(guān)閉他們。在以上例子中,錯(cuò)誤輸出流沒(méi)有數(shù)據(jù)要輸出,標(biāo)準(zhǔn)輸出流中有數(shù)據(jù)輸出。由于標(biāo)準(zhǔn)輸出流中的數(shù)據(jù)沒(méi)有被讀取,進(jìn)程就不會(huì)結(jié)束,錯(cuò)誤輸出流也就不會(huì)被關(guān)閉,因此在調(diào)用readLine()方法時(shí),整個(gè)程序就會(huì)被阻塞。為了解決這個(gè)問(wèn)題,可以根據(jù)輸出的實(shí)際先后,先讀取標(biāo)準(zhǔn)輸出流,然后讀取錯(cuò)誤輸出流。
但是,很多時(shí)候不能很明確的知道輸出的先后,特別是要操作標(biāo)準(zhǔn)輸入的時(shí)候,情況就會(huì)更為復(fù)雜。這時(shí)候可以采用線程來(lái)對(duì)標(biāo)準(zhǔn)輸出、錯(cuò)誤輸出和標(biāo)準(zhǔn)輸入進(jìn)行分別處理,根據(jù)他們之間在業(yè)務(wù)邏輯上的關(guān)系決定讀取那個(gè)流或者寫(xiě)入數(shù)據(jù)。
針對(duì)標(biāo)準(zhǔn)輸出流和錯(cuò)誤輸出流所造成的問(wèn)題,可以使用ProcessBuilder的redirectErrorStream()方法將他們合二為一,這時(shí)候只要讀取標(biāo)準(zhǔn)輸出的數(shù)據(jù)就可以了。
當(dāng)在程序中使用Process的waitFor()方法時(shí),特別是在讀取之前調(diào)用waitFor()方法時(shí),也有可能造成阻塞。可以用線程的方法來(lái)解決這個(gè)問(wèn)題,也可以在讀取數(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é)束。
如:
import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; |
(2)使用線程
import java.util.*; import java.io.*; |
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 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 public class Test6 { // process error and output message // start to watch //wait for exit //print the content from ERROR and OUTPUT } catch (Throwable t) { |
上述內(nèi)容就是Java中怎么執(zhí)行其它程序,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。