`
天泪不死
  • 浏览: 27492 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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缺陷透彻的梳理了一遍。
为了不重复别的话,很多基础知识没有描述,本着重点解决问题和存在的问题。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics