使用Runtime.getRuntime().exec()方法可以在java程序里运行外部程序。
一般的应用程序可以直接使用第一版本,当有环境变量传递的时候使用后面的版本。其中2和6版本可以传递一个目录,标识当前目录,因为有些程序是使用相对目录的,所以就要使用这个版本。
cmd.exe /c start
使用DOS命令(比如dir)时也要使用到调用。如果想与调用的程序进行交互,那么就要使用该方法的返回对象Process了,通过Process的getInputStream(),getOutputStream()和getErrorStream()方法可以得到输入输出流,然后通过InputStream可以得到程序对控制台的输出信息,通过OutputStream可以给程序输入指令,这样就达到了程序的交换功能。
用Java编写应用时,有时需要在程序中调用另一个现成的可执行程序或系统命令,这时可以通过组合使用Java提供的Runtime类和Process类的方法实现。下面是一种比较典型的程序模式:
2
3
4
在上面的程序中,第一行的“.\\p.exe”是要执行的程序名,Runtime.getRuntime()返回当前应用程序的Runtime对象,该对象的exec()方法指示Java虚拟机创建一个子进程执行指定的可执行程序,并返回与该子进程对应的Process对象实例。通过Process可以控制该子进程的执行或获取该子进程的信息。第二条语句的目的等待子进程完成再往下执行。
但在windows平台上,如果处理不当,有时并不能得到预期的结果。下面是笔者在实际编程中总结的几种需要注意的情况:
2
2
3
4
5
6
7
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 { -
-
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(new InputStreamReader(fis)); -
String line = null; -
//逐行读取输出到控制台 -
while ((line = br.readLine()) != null) { -
System.out.println(line); -
} -
} catch (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(new InputStreamReader(fis)); -
String line = null; -
//逐行读取输出到控制台 -
while ((line = br.readLine()) != null) { -
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 = -
new BufferedReader( new InputStreamReader( inputStream ) ); -
-
//save first line -
if( ( lineToRead = bufferedRreader.readLine() ) != null ){ -
resultStringBuffer.append( lineToRead ); -
} -
-
//save next lines -
while( ( lineToRead = bufferedRreader.readLine() ) != null ){ -
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; - }
- //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( new InputStreamReader( inputStream ) ); -
-
//save first line -
if( ( lineToRead = bufferedRreader.readLine() ) != null ){ -
resultStringBuffer.append( lineToRead ); -
} -
-
//save next lines -
while( ( lineToRead = bufferedRreader.readLine() ) != null ){ -
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
import
import
import
import
import
public
}
外部Bat文件:
列表2
cmd.exe
javac
cmd.exe
rem
time
列表3:
import
import
import
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