从JAVA 1.5版本开始,JAVA新增了ProcessBuilder,专门用于调用外部进程,且能快速创建一个指定了环境的进程与子进程,极大地增强了进程的复用性,示例代码如下:
// 定义在FileNameGetProcess.java文件中
static List<String> call() throws Exception {
List<String> fileNames = Lists.newArrayList();
// 设置了环境变量DIR,针对Windows环境
List<String> commands = Lists.newArrayList("cmd.exe", "/c", "dir /w", "%DIR%");
ProcessBuilder pb = new ProcessBuilder(commands);
// 设置环境变量
Map<String, String> env = pb.environment();
env.put("DIR", "D:\\");
// 启动进程
Process pr = pb.start();
InputStream is = pr.getInputStream(); // 获得输入流
InputStreamReader isr = new InputStreamReader(is, "GBK");// 创建输入读流,编码方式为GBK
BufferedReader br = new BufferedReader(isr); // 创建读缓冲对象
while ((line = br.readLine()) != null) {
// 循环读取数据
fileNames.add(line);
}
pr.waitFor();
return fileNames;
}
在上述代码的执行中,一定要密切注意命令参数,JAVA执行命令都通过实体文件的方式,所以执行的命令如果没有物理文件支持,如dir,则一定要采用“cmd.exe”的方式,而对于有物理文件支持的命令,如C:\Windows\System32文件下的ipconfig命令以及脚本,直接给出文件调用路径及命令即可,如:
// 直接调用
ProcessBuilder pb = new ProcessBuilder("ipconfig", "/all");
Process pr = pb.start();
// 直接调用
ProcessBuilder pb = new ProcessBuilder("E:\\list.cmd");
Process pr = pb.start();
如果违反了上述规则,则一定会出现如下错误:
Exception in thread "main" java.io.IOException: Cannot run program "dir c:\": CreateProcess error=2, 系统找不到指定的文件。
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
at com.cnitsec.mirana.process.CMDExecute.main(CMDExecute.java:106)
Caused by: java.io.IOException: CreateProcess error=2, 系统找不到指定的文件。
at java.lang.ProcessImpl.create(Native Method)
at java.lang.ProcessImpl.<init>(ProcessImpl.java:386)
at java.lang.ProcessImpl.start(ProcessImpl.java:137)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
... 1 more
为了使进程的执行具有更好的响应性,我们可以使用Future对进程执行的任务进行封装,如下:
ExecutorService executor = Executors.newSingleThreadExecutor();
// 获取执行结果
Future<List<String>> results = executor.submit(FileNameGetProcess::call);
List<String> strs = results.get();
for(String str: strs) {
System.out.println(str);
}
// 一定要记得关闭,否则主线程无法结束
executor.shutdown();
结论
外部进程的执行状态可以通过Future方式来获取执行结果,ProcessBuilder.start()还支持InterruptedException,所以外部进程在执行过程中,还支持主线程的中断信号。