【Java&CMD】java执行CMD命令

一、java本身API执行CMD

 

Process ps = Runtime.getRuntime().exec(cmd);
ps.waitFor();//等待线程结束

 

waitFor是为了保证cmd命令在后续任务执行前就完成。但是如果cmd命令存在不少的输出信息或者错误信息,在执行waitFor时,会发生阻塞。

为什么会堵塞呢?原因是当调用exec(cmd)后,JVM会启动一个子进程,该进程会与JVM进程建立3个管道连接,标准输入,标准输出和标准错误流。假设该程序不断在向标准输出流和标准错误流写数据,而JVM不读取,数据会暂时缓冲在Linux的缓冲区,缓冲区满后该程序将无法继续写数据,所以Java程序就会堵塞在waitfor(),永远无法结束。

解决办法就是增加两个线程,一个线程负责读标准输出流,另一个负责读标准错误流,这样子数据就不会积压在缓冲区,程序就能够顺利运行。不一定两个线程都需要,可以根据CMD命令的实际情况,是输出流导致阻塞,还是错误流导致的。

处理输出流的公共线程类:

 

public class ProcessStreamHandle extends Thread{
	private InputStream is;
	private List<String> list;//用于保存输出流信息,方便程序读取使用
	public ProcessStreamHandle(InputStream is,List<String> list) {
		this.is = is;
		this.list = list;
	}
	@Override
	public void run() {
		BufferedReader br1 = new BufferedReader(new InputStreamReader(is));   
        try {   
            String line1 = null;   
            while ((line1 = br1.readLine()) != null) {  
            	list.add(line1);
            }   
        }catch (IOException e) {   
             e.printStackTrace();   
        }finally{   
             try {   
            	 is.close();//关闭通道,避免因过多通道未关而产生:java.io.IOException: Too many open files异常   
             } catch (IOException e) {   
                e.printStackTrace();   
             }   
        }   
   }   
}

执行CMD命令主程序:

 

 

public class JavaCmd {

	public static void main(String[] args) {
		test();
	}
	public static void test(){
		String rootPath2 = "\""+"D:\\Program Files (x86)\\cwRsync\\bin";//在含空格路径前后加双引号
		String cmd = rootPath2+File.separator+"rsync.exe"+"\""+" -vr --delete --progress --ignore-errors /cygdrive/E/test/rsync/a/ /cygdrive/E/test/rsync/b ";
		try {
			Process ps = Runtime.getRuntime().exec(cmd);
			//获取进程的标准输入流   
			final InputStream is1 = ps.getInputStream();  
			List<String> inputStrList = new ArrayList<String>();
			//获取进城的错误流   
			final InputStream is2 = ps.getErrorStream();   
		    List<String> errorStrList = new ArrayList<String>();
			//启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流   
			new ProcessStreamHandle(is1,inputStrList).start();
			new ProcessStreamHandle(is2,errorStrList).start();
			ps.waitFor();//等待线程结束
			System.out.println("over");
			printList(inputStrList);
			printList(errorStrList);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	public static void printList(List<String> list){
        for (String string : list) {
            System.out.println(string);
        }
    }
}

注:

 

1、cmd命令如果包含空格将无法正确执行。解决办法就是:在执行路径的路径前后添加双引号(" \" ")。

2、waitFor只适用于能够结束的线程,比如你使用命令启动mysql服务,启动程序确实执行完毕,但是线程任然在执行中,就是你的mysql线程。所以使用waitFor要慎重。

二、Commons-IO下的Ant包

 

public class AntCmdTest {

	public static void main(String[] args) {
		try {
			test();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void test() throws IOException{
		ByteArrayOutputStream bOutputStream = new ByteArrayOutputStream();
		ExecuteWatchdog wdog = new ExecuteWatchdog(2000l);//cmd命令最大执行时间
		Execute exec = new Execute(new PumpStreamHandler(bOutputStream), wdog);
		String cmd[]={"notepad ","E:\\\\1.txt"};//使用notepad打开1.txt
		exec.setCommandline(cmd);
		int exitStatus = exec.execute();
		if(exitStatus==0&&!wdog.killedProcess()){
			System.out.println((new StringBuilder()).append(Arrays.asList(cmd)).append(" :").append(bOutputStream).toString());
		}
		String cmd2[] = {"\"D:\\Program Files (x86)\\cwRsync\\bin\\rsync.exe\"","-vr","--delete","/cygdrive/E/test/rsync/a/","/cygdrive/E/test/rsync/b "};
		exec.setCommandline(cmd2);
		int exitStatus2 = exec.execute();
		if(exitStatus2==0&&!wdog.killedProcess()){
			System.out.println((new StringBuilder()).append(Arrays.asList(cmd2)).append(" :").append(bOutputStream).toString());
		}
	}
}

注:

 

1、ExecuteWatchdog中设置了执行最大时间,得确保你的CMD命令能够执行完毕,所以稍微设置大些。

2、第一个cmd:1.txt将被notepad打开,2秒后关闭;第二个也执行2秒,如果文件过多将无法同步完全。


三、其他

数组执行:Linux+Windows

exec.Command("/bin/sh", "-c", cmd)
exec.Command("cmd", "/C", cmd)


 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qqchaozai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值