Process应用之惑

很多时候,我们需要调用系统命令来做些处理。比如,在程序中ping设备是否能连接,执行数据库的自动备份,以及程序的重启。这时候我们必须要使用Process类来完成这些功能。
一般情况下,我们都会将命令执行过程中的信息输出,以便检查问题。但有时候我们还需知道这个执行的进程在什么时候结束,因为不仅要知道结束了,还要知道该进程完成时返回的结果。
可能会说,这些不都是API已经给提供好的吗?过程中的消息可以用process.getInputStream()获取,进程最终结果可以由process.waitFor()得到。的确,这些看似可以办到,但其实,里面有陷阱。

首先以Runtime来创建我们需要的Process对象例子:
Process process = null;
BufferedReader reader=null;
try {
process = Runtime.getRuntime().exec("ping 192.168.0.125");
reader=new BufferedReader(new InputStreamReader(process.getInputStream()));
String line=null;
while((line=reader.readLine())!=null){
System.out.println(line);
}
int result=process.waitFor();
System.out.println(result);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

这个例子我们只是简单的ping了一个IP,用getInputStream()输出过程信息,然后用process.waitFor()得到执行完成后的结果。会发现一点问题都没有。
1.此时如果把process.getInputStream()换成process.getErrorStream(),就只有一个结果输出了。
2.如果把执行的内容换成EXP导个oralce数据库的命令呢!发现过程信息和结果值都有,但是如果拿到一个server上去跑跑,又发现总是会报错,rocess has not exited 进程未停止....在网上查询,很多人会告诉你是输出流导致进程阻塞,发生死锁了。
3.此时你再把process.getErrorStream()改回process.getInputStream(),发现啥也没有,而且程序不会停掉。这是肯定的,输出流又导致进程阻塞了。
查API得知Process所有标准 io(即 stdin,stdout,stderr)操作都将通过三个流 (getOutputStream(),getInputStream(),getErrorStream()) 重定向到父进程。那为什么执行系统自带命令就能用getInputStream()获取到信息而不是系统自带命令就一定要用getErrorStream()来获取信息呢!惑之...待高手解答...
获取进程返回结果有两个方法exitValue()和waitFor()。往往会发现流的堵塞无法使其得到值就报异常了。这个网上也有解答方法。即要清空getInputStream()和getErrorStream()这两个流。而且两个流的清空一定是异步的。
static void drainInBackground(final InputStream is) {
new Thread(new Runnable(){
public void run(){
try{
while( is.read() >= 0 );
} catch(IOException e){
// return on IOException
}
}
}).start();
}


有没有好的办法不写这个清空流的方法呢!或是还不明白,那就直接用ProcessBuilder来创建Process对象吧!ProcessBuilder已经给出了这方面的解决方案,但是必须要注意的是ProcessBuilder的redirectErrorStream方法。查API可知晓,redirectErrorStream方法设置为ture的时候,会将getInputStream(),getErrorStream()两个流合并,自动会清空流,无需我们自己处理。如果是false,getInputStream(),getErrorStream()两个流分开,就必须自己处理,程序如下:
try {
ProcessBuilder pbuilder=new ProcessBuilder("ping","192.168.0.125");
pbuilder.redirectErrorStream(true);
process=pbuilder.start();
reader=new BufferedReader(new InputStreamReader(process.getInputStream()));
String line=null;
while((line=reader.readLine())!=null){
System.out.println(line);
}
int result=process.waitFor();
System.out.println(result);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

现在无论你调用的是系统自带命令还是配置环境变量的其他命令,getInputStream()流都能给你过程信息和执行结果。
如果redirectErrorStream设置为false,那结果会和上面所说一样。

最后,还要说的是,得到的process.waitFor()结果。别以为这个执行结果值是一层不变的0,API没有给出具体有多少种类型的返回值,就我测试的结果来看:
0 successfully
1 failure
3 successfully! but a warning
....2没有测试出来

经过一个上午的不断测试,找源码来看,查资料,终于将这个已经没有认真理会的API缺陷透彻的梳理了一遍。
为了不重复别的话,很多基础知识没有描述,本着重点解决问题和存在的问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值