Java调用外部程序解决方案
关键字 Java 外部程序 CMD 进程 调用 Process
最近接触一个需求,是利用Java调用本地命令行程序,并希望Java程序能与该命令行程序进行交互,Java对该程序的操作如同在终端中对程序的操纵一样。
在技术调研的过程中,遇到了几个问题:
- 如何Java调用命令行程序
- 如何利用Java向命令行程序的标准输入写入字符流
- 如何利用Java即时地得到命令行程序的标准输出流。
- 如何利用Java即时地得到命令行程序的标准错误流
一、调用命令行程序
这个很简单,Java调用的方法为
Process process = Runtime.getRuntime().exec(“command name”);
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了命令,但是外部程序并没有得到他,就一直阻塞,这是开发者经常会遇到的问题。
三、标准输入和错误输入
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)) {
// We have a new segment of input, so process it as a String..
System.out.print(new String(inBuffer, 0, i));
}
负责接收外部程序的输出信息
线程三、
// Read the ErrorStream in a loop until we find no more bytes to read..
for (int i = 0; i > -1; i = pErrorStream.read(errBuffer)) {
// We have a new segment of error, so process it as a String..
Systerm.err.print(new String(errBuffer, 0, i));
}
负责接收外部程序的错误输出信息
在适当的地方,调用outputWriter.print(string);向程序写入字符流。