不积跬步,无以至千里。不积小流,无以成江海。

今天为了博客能实现自动部署,写了一个Java小程序调用cmd命令来实现自动部署hexo并备份博客。

java中提供了两种方式来调用exe或shell程序:

  1. 使用Runtime.getRuntime().exec()
  2. 使用new ProcessBuilder().start()

下面我在实际使用中的代码如下,这里使用的是new ProcessBuilder().start()的方式,调用cmd执行命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public String deployHexo() throws Exception{

String cmd = "cd " + HEXO_DIR + " && hexo clean && hexo g && hexo d";
List<String> cmds = new LinkedList<String>();
// cmds.add("sh");
cmds.add("cmd.exe");
// cmds.add("-c");
cmds.add("/c");
cmds.add(cmd);
ProcessBuilder pb = new ProcessBuilder(cmds);
//重定向到标准输出
pb.redirectErrorStream(true);
Process p = pb.start();
p.waitFor(3, TimeUnit.SECONDS);
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
String result = sb.toString();
return result;
}

这个方法会在调用后返回命令行处理的输出结果。如果是在Linux平台中调用,则把上面的5 -8行的命令改成如下即可:

1
2
3
4
        cmds.add("sh");
// cmds.add("cmd.exe");
cmds.add("-c");
// cmds.add("/c");

Runtime.getRuntime().exec()方式的使用与上面的代码差别不大,将第4-10行替换成如下,另外可删除第12行即可:

1
2
String[] cmdArray ={"cmd.exe","/c",cmd};
Process p = Runtime.getRuntime().exec(cmdArray);

我们使用这两种方式执行命令时,都会返回一个Process 并创建一个子线程。在Jdk文档中对它有下列描述:

默认情况下,创建的子进程没有自己的终端或控制台。 其所有的标准I/ O(即标准输入,标准输出,标准错误)操作将被重定向到父进程,在那里他们可以经由使用所述方法获得的流进行访问getOutputStream()getInputStream()getErrorStream()。 父进程使用这些流将输入提供给子进程并从子进程获取输出。 因为一些本地平台只为标准输入和输出流提供有限的缓冲区大小,因此无法及时写入输入流或读取子进程的输出流可能导致子进程阻塞甚至死锁。

我在使用过程中也遇到了进程阻塞的情况,因为缓冲区满了后,没有对缓冲区进行清空,数据也写不进才会阻塞卡住。因此我们在使用这两种方式执行命令操作时一定要对其子线程标准I/O进行处理。