大家都知道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),就可以使错误输出流合并到标准输出流,这样我们就只需要读取标准输出流就可以完全解决问题了,代码如下:


1
private 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
} 还是也介绍下使用线程来分别读取错误输出流和标准输出流吧:


1
import java.util.*;
2
import java.io.*;
3
4
class StreamWatch extends Thread
{
5
InputStream is;
6
7
String type;
8
9
ListString> output = new ArrayListString>();
10
11
boolean debug = false;
12
13
StreamWatch(InputStream is, String type)
{
14
this(is, type, false);
15
}
16
17
StreamWatch(InputStream is, String type, boolean debug)
{
18
this.is = is;
19
this.type = type;
20
this.debug = debug;
21
}
22
23
public 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
42
public ListString> getOutput()
{
43
return output;
44
}
45
}
46
47
public class Test5
{
48
public 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
好了,今天就先写到这里吧。