前言

最近使用Java编写用于测试平台的工具类,有个需求是在java中调用命令行语句并获取输出,在Java中有两种方式可以完成这个任务。一个是Runtime.getRuntime().exec()(java1.5之前),java1.5之后提供了ProcessBuilder类来构建进程。由于Runtime的方法不够灵活,而且我们项目不需要兼容老版本java,这里用ProcessBuilder来构建这个工具类。

PS: 代码中写了一些方便的adb和adbshell方法,完全可以定制自己的快捷方法。为防止线程阻塞,我们用了另一个线程读取线程的输出流。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package com.nata;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* Author: Calvin Meng
* Blog: mclspace.com Email: rdmclin2@gamil.com
* Update: 2016-01-20 14:23
*/
public class ShellKit {
/**
* Run shell command starting with 'adb'
*
* @param cmd command list to execute
* @return Any Output
*/
public static String adb(List<String> cmd) {
cmd.add(0, "adb");
return command(cmd);
}
/**
* Run shell command starting with 'adb'
*
* @param cmd command to execute ,tokenize with whitespace
* @return Any Output
*/
public static String adb(String cmd) {
String[] splits = cmd.split(" ");
return adb(splits);
}
/**
* Run shell command starting with 'adb'
*
* @param cmd command string array to execute
* @return Any Output
*/
public static String adb(String... cmd) {
ArrayList<String> cmds = new ArrayList<>();
cmds.add("adb");
for (String part:cmd
) {
cmds.add(part) ;
}
return command(cmds);
}
/**
* Run shell command starting with 'adb shell'
*
* @param cmd command list to execute
* @return running Any Output
*/
public static String adbShell(List<String> cmd) {
cmd.add(0, "shell");
cmd.add(0, "adb");
return command(cmd);
}
/**
* Run shell command starting with 'adb shell'
*
* @param cmd command to execute ,tokenize with whitespace
* @return Any Output
*/
public static String adbShell(String cmd) {
String[] splits = cmd.split(" ");
return adbShell(splits);
}
/**
* Run shell command starting with 'adb shell'
*
* @param cmd command string array to execute
* @return Any Output
*/
public static String adbShell(String... cmd) {
ArrayList<String> cmds = new ArrayList<>();
cmds.add("adb");
cmds.add("shell");
for (String part:cmd
) {
cmds.add(part) ;
}
return command(cmds);
}
/**
* Execute a shell command and return its output
*
* @param command command to execute
* @return process executed
*/
public static String command(List<String> command) {
//set redirectErrorStream to be true to cross output streams
ProcessBuilder pb = new ProcessBuilder(command).redirectErrorStream(true);
String output = "";
try {
Process process = pb.start();
IOThreadHandler outputHandler = new IOThreadHandler(
process.getInputStream());
outputHandler.start();
//wait for the process to stop
process.waitFor();
//in case the process stopped before the thread
outputHandler.join();
output = outputHandler.getOutput();
} catch (InterruptedException | IOException e) {
e.printStackTrace();
}
return output;
}
/**
* Thread to drain the output of cmd running
*/
private static class IOThreadHandler extends Thread {
private InputStream inputStream;
private StringBuilder output = new StringBuilder();
IOThreadHandler(InputStream inputStream) {
this.inputStream = inputStream;
}
public void run() {
try (Scanner br = new Scanner(new InputStreamReader(inputStream))) {
String line = null;
while (br.hasNextLine()) {
line = br.nextLine();
output.append(line).append(System.getProperty("line.separator"));
}
}
}
public String getOutput() {
return output.toString();
}
}
//mininal unit test
public static void main(String[] args) {
ArrayList<String> cmds = new ArrayList<>();
cmds.add("devices");
System.out.println(ShellKit.adb(cmds));
cmds.clear();
cmds.add("getprop");
cmds.add("ro.boot.serialno");
System.out.println(ShellKit.adbShell(cmds));
}
}

参考资料

When Runtime.exec() won’t

这篇文章很不错,建议一看,只是发布时间有点晚了。

runtime.exec 和 processbuilder的区别