使用Runtime.getRuntime().exec()方法可以在java程序裏運行外部程序。
cmd.exe /c start
使用DOS命令(比如dir)時也要使用到調用。如果想與調用的程序進行交互,那麼就要使用該方法的返回對象Process了,通過Process的getInputStream(),getOutputStream()和getErrorStream()方法可以得到輸入輸出流,然後通過InputStream可以得到程序對控制檯的輸出信息,通過OutputStream可以給程序輸入指令,這樣就達到了程序的交換功能。
用Java編寫應用時,有時需要在程序中調用另一個現成的可執行程序或系統命令,這時可以通過組合使用Java提供的Runtime類和Process類的方法實現。下面是一種比較典型的程序模式:
3
在上面的程序中,第一行的“.\\p.exe”是要執行的程序名,Runtime.getRuntime()返回當前應用程序的Runtime對象,該對象的exec()方法指示Java虛擬機創建一個子進程執行指定的可執行程序,並返回與該子進程對應的Process對象實例。通過Process可以控制該子進程的執行或獲取該子進程的信息。第二條語句的目的等待子進程完成再往下執行。
但在windows平臺上,如果處理不當,有時並不能得到預期的結果。下面是筆者在實際編程中總結的幾種需要注意的情況:
2
4
6
Java調用外部程序解決方案
關鍵字 Java 外部程序 CMD 進程 調用 Process
最近接觸一個需求,是利用Java調用本地命令行程序,並希望Java程序能與該命令行程序進行交互,Java對該程序的操作如同在終端中對程序的操縱一樣。
在技術調研的過程中,遇到了幾個問題:
- 如何Java調用命令行程序
- 如何利用Java向命令行程序的標準輸入寫入字符流
- 如何利用Java即時地得到命令行程序的標準輸出流。
- 如何利用Java即時地得到命令行程序的標準錯誤流
一、調用命令行程序
這個很簡單,Java調用的方法爲
Process的JavaDoc地址:http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Process.html
二、標準輸出
注意,在這裏標準輸出指的是Java程序以標準輸出的方式發出字節流,這些字節流會以標準輸入的方式進入被調用的命令行程序
OutputStream pOutputStream = process.getOutputStream();
PrintWriter outputWriter = new PrintWriter(pOutputStream,true);
outputWriter.print(string);
PrintWriter的第二個構造參數一定要選爲true,這樣才能自動flush進入外部程序,不然,沒有Flush,你向被調用程序所寫的輸入,只有在下一次緩衝被Flush的時候才能發揮作用,這樣,當你的輸入很少時,你雖然在代碼裏print了命令,但是外部程序並沒有得到他,就一直阻塞,這是開發者經常會遇到的問題。
此處我用如上代碼並不能解決問題,我的代碼如下,成功運行:
Process p = run.exec(cmd);// 啓動另一個進程來執行命令
OutputStream out =p.getOutputStream();
三、標準輸入和錯誤輸入
private InputStream pErrorStream = process.getErrorStream();
private InputStream pInputStream =process.getInputStream();
這兩個輸入是用來接受外部程序的反饋的,外部程序通常會向標準終端打印字符,這些字符會通過這兩個流得到,經過測試,我們發現一個問題,如果外部程序在輸出信息時,沒有用flush也會出現問題,比如C語言的程序
scanf(“%d”, &i);
printf(“%d”, i);
這段代碼在運行時,雖然在終端裏會即時的顯示出來,但是卻不能及時地發送給pInputStream,這是因爲程序輸出使用了緩衝機製造成的,所以,這造成的困難是如果你沒有外部程序的源碼,你就很難將輸出即時顯示出來,我目前還沒有找到解決方案,如果你有源碼就好辦了,在源碼中設置輸出爲即時flush就好了,我用笨辦法來說明:
scanf(“%d”, &i);
printf(“%d”, i);
fflush(stdout);
這樣,fflush(stdout)之後,pInputStream就會得到輸入了。
四、綜合
下面我們用三個線程來進行一個簡單的與外部程序的交互過程的設計
線程一、
process.waitFor(),負責建立線程並等待線程結束
線程二、
for (int i = 0; i > -1; i =pInputStream.read(inBuffer)) {
}
負責接收外部程序的輸出信息
線程三、
負責接收外部程序的錯誤輸出信息
在適當的地方,調用outputWriter.print(string);向程序寫入字符流。
===========================================================================================================
1java調用外部程序的方法
在一個java應用中,可能會遇到這樣的需求,就是需要調用一些外部的應用做一些處理,比如調用excel,然後在繼續程序的運行。
下面就開始進入java調用外部程序的一些演示,讓java應用更加靈活。
1:最簡單的演示:
Runtime.getRuntime().exec("notepad.exe");
記事本被打開了是吧。
2:傳遞應用程序的參數:
Runtimeruntime=Runtime.getRuntime();
String[]commandArgs={"notepad.exe","c:/boot.ini"};
runtime.exec(commandArgs);
現在不單單打開了記事本,而且還裝載了boot.ini文件是吧。
現在已經完全解決了調用外部程序的問題,不是嗎,但是大家會發現exec方法是有返回值,那麼繼續我們的演示吧。
1:Process的waitFor:
Runtimeruntime=Runtime.getRuntime();
String[]commandArgs={"notepad.exe","c:/boot.ini"};
Processprocess=runtime.exec(commandArgs);
intexitcode=process.waitFor();
System.out.println("finish:"+exitcode);
執行上面的代碼以後發現不同的地方了嗎,waitFor會使線程阻塞,只有外部程序退出後纔會執行System.out.println("finish:"+exitcode);
這個功能很有用是吧,因爲多數時候你都需要等待用戶處理完外部程序以後才繼續你的java應用。
2:Process的destroy:
Runtimeruntime=Runtime.getRuntime();
String[]commandArgs={"notepad.exe","c:/boot.ini"};
final Processprocess=runtime.exec(commandArgs);
new Thread(newRunnable(){
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e){}
process.destroy();
}}).start();
intexitcode=process.waitFor();
System.out.println("finish:"+exitcode);
這個演示稍微複雜了一些,如果你等待5秒,就會發現記事本自動關閉了,是的,這個就是destroy方法的作用,強制關閉調用的外部程序。
不用我解釋了吧,這是非常有用的方法。
以上的部分已經足夠你調用並控制你的外部應用了。如果需要更詳細的信息,看javadoc文檔吧。
最後的說明:ProcessBuilder這個1.5新增的類也可以完成同樣的任務,Runtime就是調用了這個類。
============================================================================================================
Java調用外部程序命令主要用到兩個類:
java.lang.Runtime
每個 Java 應用程序都有一個 Runtime 類實例,使應用程序能夠與其運行的環境相連接。可以通過 getRuntime方法獲取當前運行時。應用程序不能創建自己的 Runtime 類實例。
java.lang.Process
ProcessBuilder.start() 和 Runtime.exec 方法創建一個本機進程,並返回 Process子類的一個實例,該實例可用來控制進程並獲取相關信息。Process類提供了執行從進程輸入、執行輸出到進程、等待進程完成、檢查進程的退出狀態以及銷燬(殺掉)進程的方法。 對於帶有 Process 對象的Java 進程,沒有必要異步或併發執行由 Process 對象表示的進程。
下面Java調用Windows命令的例子:
-
import
java.io.IOException; -
import
java.io.BufferedReader; -
import
java.io.InputStream; -
import
java.io.InputStreamReader; -
-
-
public
class TestCmd { -
-
static void main(String args[]) { -
testWinCmd(); -
dirOpt(); -
} -
-
static void testWinCmd() { -
System.out.println( -
Runtime runtime = Runtime.getRuntime(); -
System.out.println(runtime.totalMemory()); -
System.out.println(runtime.freeMemory()); -
System.out.println(runtime.maxMemory()); -
System.out.println(runtime.availableProcessors()); -
{ -
-
runtime.exec( -
runtime.exec( Files//Microsoft );Office//OFFICE11//winword.exe c://test.doc" -
-
runtime.exec( -
-
runtime.exec( /c );dir " -
runtime.exec( /c );dir c://" -
-
//
//-------------- 文件操作 -------------- -
-
runtime.exec( /c );copy c://x.bat d://x.txt" //copy並改名 -
runtime.exec( /c );rename d://x.txt x.txt.bak" //重命名 -
runtime.exec( /c );move d://x.txt.bak c://" //移動 -
runtime.exec( /c );del c://x.txt.bak" //刪除 -
-
目錄操作 -------------- -
runtime.exec( /c );md c://_test" //刪除 -
} (IOException e) { -
e.printStackTrace(); -
} -
} -
-
-
static void dirOpt() { -
System.out.println( -
Process process; -
{ -
-
process = Runtime.getRuntime().exec( -
-
InputStream fis = process.getInputStream(); -
-
BufferedReader br = BufferedReader( newInputStreamReader(fis)); -
String line = -
-
((line null)= br.readLine()) != { -
System.out.println(line); -
} -
} (IOException e) { -
e.printStackTrace(); -
} -
} -
}
-
import
java.io.IOException; -
import
java.io.BufferedReader; -
import
java.io.InputStream; -
import
java.io.InputStreamReader; -
-
-
public
class TestCmd { -
-
public static void main(String args[]) { -
testWinCmd(); -
dirOpt(); -
} -
-
public static void testWinCmd() { -
System.out.println("------------------testWinCmd()--------------------"); -
Runtime runtime = Runtime.getRuntime(); -
System.out.println(runtime.totalMemory()); -
System.out.println(runtime.freeMemory()); -
System.out.println(runtime.maxMemory()); -
System.out.println(runtime.availableProcessors()); //處理器數 -
try { -
//執行一個exe文件 -
runtime.exec("notepad"); -
runtime.exec("C://Program Files//Microsoft );Office//OFFICE11//winword.exe c://test.doc" -
//執行批處理 -
runtime.exec("c://x.bat"); -
//執行系統命令 -
runtime.exec("cmd /c );dir " -
runtime.exec("cmd /c );dir c://" -
-
//
//-------------- 文件操作 -------------- -
-
runtime.exec("cmd /c );copy c://x.bat d://x.txt" //copy並改名 -
runtime.exec("cmd /c );rename d://x.txt x.txt.bak" //重命名 -
runtime.exec("cmd /c );move d://x.txt.bak c://" //移動 -
runtime.exec("cmd /c );del c://x.txt.bak" //刪除 -
-
//-------------- 目錄操作 -------------- -
runtime.exec("cmd /c );md c://_test" //刪除 -
} catch (IOException e) { -
e.printStackTrace(); -
} -
} -
-
-
public static void dirOpt() { -
System.out.println("------------------dirOpt()--------------------"); -
Process process; -
try { -
//執行命令 -
process = Runtime.getRuntime().exec("c://x.bat"); -
//取得命令結果的輸出流 -
InputStream fis = process.getInputStream(); -
//用一個讀輸出流類去讀 -
BufferedReader br = new BufferedReader( newInputStreamReader(fis)); -
String line = null; -
//逐行讀取輸出到控制檯 -
while ((line null)= br.readLine()) != { -
System.out.println(line); -
} -
} catch (IOException e) { -
e.printStackTrace(); -
} -
} -
}
下面Java調用Perl命令的例子:
-
//PerlExecResult
is a user-defined class, It just saves execPerl's results -
public
static PerlExecResult execPerl(){ -
String[]
cmd "perl",= { "pprogram.pl", "param1", "param2" }; -
StringBuffer
resultStringBuffer new= StringBuffer(); -
String
lineToRead "";= -
-
//get
Process to execute perl, get the output and exitValue -
int
exitValue 0;= -
try{
-
Process proc = Runtime.getRuntime().exec( cmd ); -
InputStream inputStream = proc.getInputStream(); -
BufferedReader bufferedRreader = -
BufferedReader( newInputStreamReader( inputStream ) ); -
-
first line -
( nulllineToRead = bufferedRreader.readLine() ) != ){ -
resultStringBuffer.append( lineToRead ); -
} -
-
next lines -
( nulllineToRead = bufferedRreader.readLine() ) != ){ -
resultStringBuffer.append( ); -
resultStringBuffer.append( lineToRead ); -
} -
reading STDOUT first, then STDERR, exitValue last -
proc.waitFor(); for reading STDOUT and STDERR over -
exitValue = proc.exitValue(); -
}catch(
Exception ex ){ -
resultStringBuffer = StringBuffer( ""); -
exitValue = -
}
-
-
PerlExecResult
perlExecResult new= PerlExecResult( resultStringBuffer.toString(), exitValue ); -
return
perlExecResult; -
}
-
//PerlExecResult
is a user-defined class, It just saves execPerl's results -
public
static PerlExecResult execPerl(){ -
String[]
cmd = { "perl", "pprogram.pl", "param1", "param2" }; -
StringBuffer
resultStringBuffer = new StringBuffer(); -
String
lineToRead = ""; -
-
//get
Process to execute perl, get the output and exitValue -
int
exitValue 0;= -
try{
-
Process proc = Runtime.getRuntime().exec( cmd ); -
InputStream inputStream = proc.getInputStream(); -
BufferedReader bufferedRreader = -
new BufferedReader( newInputStreamReader( inputStream ) ); -
-
//save first line -
if( ( nulllineToRead = bufferedRreader.readLine() ) != ){ -
resultStringBuffer.append( lineToRead ); -
} -
-
//save next lines -
while( ( nulllineToRead = bufferedRreader.readLine() ) != ){ -
resultStringBuffer.append( "/r/n" ); -
resultStringBuffer.append( lineToRead ); -
} -
//Always reading STDOUT first, then STDERR, exitValue last -
proc.waitFor(); //wait for reading STDOUT and STDERR over -
exitValue = proc.exitValue(); -
}catch(
Exception ex ){ -
resultStringBuffer = new StringBuffer( ""); -
exitValue = 2; -
}
-
-
PerlExecResult
perlExecResult = new PerlExecResult( resultStringBuffer.toString(), exitValue ); -
return
perlExecResult; -
}
=================================================================================================
幾乎所有的Java集成開發環境都需要調用外部進程進行Java程序的構建,編譯,運行和調試,Eclipse,NetBeans,JBuilder和IntellijIDLE概莫例外。在執行過程中,將提示信息以黑色全部打印在控制檯裏,將異常和錯誤以紅色方式打印。以非常醒目交互體驗讓程序員遠離枯燥和乏味。
現在讓我們以Eclipse爲例來看看它如何工作的,以揭開它神祕面紗,探究隱藏在後面的祕密。
上篇主要介紹了JAVAIDE Console通過採用Runtime.getRuntime.exec()執行外部程序後,將返回一個Process對象.Process對象能返回三個流:
getInputStream(),對應Process程序的標準輸出流。
getErrorStream(), 對應Process程序的標準錯誤輸出流。
getOutputStream();對應Process程序的標準輸入流。
函數名之所以與Process程序的方向相反,原因是站在Java Host程序的角度講的。
現在我們應用此原理來仿真IDE 執行外部程序的過程。
列表1:ConsoleSimulator.java
public
}
外部Bat文件:
列表2
cmd.exe
javac
cmd.exe
rem
time
列表3:
public
}
綜上,雖然沒有在自己的GUI裏將stdout和stderr進行說明,只是用ERROR>提示符和INFO>提示符進行演示,但是完全IDEConsole的原理。對ConsoleSimulator稍加修改,完全放入到自己的應用程序當中去。
在我們進行Java程序開發的過程當中,可能涉及到其它的應用程序,藉助這種技術,可以很好利用它們,將它們集成到自己的應用當中,將極大地縮短開發週期,何樂而不爲呢!
from:http://blog.csdn.net/zhongxiucheng/article/details/7974327(有刪改)
參看:
http://blog.csdn.net/laichunlin/article/details/8184242
http://developer.51cto.com/art/200909/149554.htm
http://www.blogjava.net/lewhwa/archive/2011/02/26/94060.html