大家都知道java调用cmd 用的是Runtime的exec()方法。该方法最终重启一个进程去执行命令,因为该方法最终调用了
ProcessBuilder:
1 public Process exec(String[] strings, String[] strings_2_, File file)
2 throws IOException {
3 return new ProcessBuilder(strings).environment(strings_2_).directory
4 (file).start();
5 } 既然是重启了一个进程,那么就存在异步的问题,但是在很多情况在更想同步的调用Runtime的exec(),那么怎么办呢?
Runtime.exec()的返回值Process提供了waitFor()方法,可以达到阻塞新进程的目的。但是只调用waitFor(),该字线程就会
一直阻塞,所以只调用waitFor()还是不够的,我们需要以读取他的输出流的方式来阻塞住线程,当输出流读取结束的
时候让阻塞结束,代码如下:
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String str = "";
while ((str = bufferedReader.readLine()) != null) {
System.out.println(str);
}
process.waitFor(); 通过读取输出流和调用process.waitFor()可以的实现调用Runtime.exec()的同步。
另外还有一种情况可以使Runtime.exec()出现阻塞,Runtime的exec()在执行时会产生两种输出流:错误输出流和标准输出流,当进程结束时会关闭这两个流,在上面的代码里只读取了标准输出流而没有导致错误输出流,由于错误输出流中的数据没有被读取,进程就不会结束,因此调用readLine()方法时整个程序就会阻塞,因此,我们不仅要读取标准输出流还要读取错误输出流,由于读取这些流都会阻塞,所以想同时读取两个流还不是那么容易,一种办法就是启动线程分别读取不同的输出流,另外一个办法就是使用ProcessBuilder来执行(前面已经说过了Runtime.exec()最终也是调用ProcessBuilder来执行的),因为ProcessBuilder有一个redirectErrorStream(),将方法设置为redirectErrorStream(true),就可以使错误输出流合并到标准输出流,这样我们就只需要读取标准输出流就可以完全解决问题了,代码如下:
1private static void execCmd(Properties properties) throws Exception {
2
3
4 File file = new File("执行命令的目录");
5
6 ListString> cmdList = new ArrayListString>();
7 cmdList.add("cmd.exe");
8 cmdList.add("/c");
9 cmdList.add(CMD);//CMD是执行的命令
10
11 ProcessBuilder pb = new ProcessBuilder(cmdList);
12 pb.directory(file);
13 pb.redirectErrorStream(true);//将错误输出流合并到标准输出流
14 Process process = pb.start();
15
16 print(process);
17 }
18
19
20 public static void print(Process process) throws Exception {
21 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
22 String str = "";
23
24 while ((str = bufferedReader.readLine()) != null) {
25 System.out.println(str);
26 }
27
28 cs.close();
29 process.waitFor();
30 } 还是也介绍下使用线程来分别读取错误输出流和标准输出流吧:
1import java.util.*;
2import java.io.*;
3
4class StreamWatch extends Thread {
5InputStream is;
6
7String type;
8
9ListString> output = new ArrayListString>();
10
11boolean debug = false;
12
13StreamWatch(InputStream is, String type) {
14 this(is, type, false);
15}
16
17StreamWatch(InputStream is, String type, boolean debug) {
18 this.is = is;
19 this.type = type;
20 this.debug = debug;
21}
22
23public void run() {
24 try {
25 PrintWriter pw = null;
26
27 InputStreamReader isr = new InputStreamReader(is);
28 BufferedReader br = new BufferedReader(isr);
29 String line = null;
30 while ((line = br.readLine()) != null) {
31 output.add(line);
32 if (debug)
33 System.out.println(type + ">" + line);
34 }
35 if (pw != null)
36 pw.flush();
37 } catch (IOException ioe) {
38 ioe.printStackTrace();
39 }
40}
41
42public ListString> getOutput() {
43 return output;
44}
45}
46
47public class Test5 {
48public static void main(String args[]) {
49 try {
50 ListString> list = new ArrayListString>();
51 ProcessBuilder pb = null;
52 Process p = null;
53
54 // list the files and directorys under C:\
55 list.add("CMD.EXE");
56 list.add("/C");
57 list.add("dir1");
58 pb = new ProcessBuilder(list);
59 pb.directory(new File("C:\\"));
60 p = pb.start();
61
62 // process error and output message
63 StreamWatch errorWatch = new StreamWatch(p.getErrorStream(),
64 "ERROR");
65 StreamWatch outputWatch = new StreamWatch(p.getInputStream(),
66 "OUTPUT");
67
68 // start to watch
69 errorWatch.start();
70 outputWatch.start();
71
72 //wait for exit
73 int exitVal = p.waitFor();
74
75 //print the content from ERROR and OUTPUT
76 System.out.println("ERROR: " + errorWatch.getOutput());
77 System.out.println("OUTPUT: " + outputWatch.getOutput());
78
79 System.out.println("the return code is " + exitVal);
80
81 } catch (Throwable t) {
82 t.printStackTrace();
83 }
84}
85}
86
87
88
好了,今天就先写到这里吧。