发新话题
打印

Java调用外部程序命令

Java调用外部程序命令

今天要写个远程重启效劳的功能, 为了开发速度, 暂时定为Java代码+WMIC命令的方法, 复杂的说, 就是应用Java调用本机使用顺序的方法。 触及到的 Java类有java. lang包里面的Runtime、Process、ProcessBuilder三个类, 以及wmic中重启效劳的命令。 由于之前 也写过这方面的东西, 所以很习气性的写出了代码:
  Process p = Runtime. getRuntime(). exec("wmic . . . ");
  BufferedReader br = new BufferedReader(new InputStreamReader(p. getInputStream()));
  String tmp = null;
  while ((tmp = br. readline()) != null) {
  System. out. println(tmp);
  }
  int exitValue = p. waitfor();
  Process p = Runtime. getRuntime(). exec("wmic . . . "); BufferedReader br = new BufferedReader(new InputStreamReader(p. getInputStream())); String tmp = null; while ((tmp = br. readline()) != null) { System. out. println(tmp); } int exitValue = p. waitfor();
  运行, 结果发现顺序不能参加, Debug发现顺序阻塞在br. readline()中了, 强迫结束顺序, 发现重启效劳的命令正常下下去了, 去掉顺序中获得规范输出的地方和获得前往结果的地方, 命令也能正常下去, 而且正常参加。
  为什么顺序会阻塞呢?Google了一下, 发现了大家的解释, 应该也是比较威望的解释吧:每个进程都有自己的规范输入、规范输出、规范错误输出, 对于某些 依赖于OS的进程, 可能其输出缓冲区很小??绻?荒芗笆钡亩脸?规范输出、标注错误输出), 将招致进程不能正常参加。 我的顺序中规范输出曾经读了, 显然原 因不是这个, 难道是错误输出缓冲区中的数据没有读出招致的?带着这个疑问, 对顺序作了一些更改:
  ProcessBuilder pb = new ProcessBuilder("wmic", . . . );
  pb. redirectErrorStream(true);
  Process p = pb. start();
  BufferedReader br = new BufferedReader(new InputStreamReader(p. getInputStream()));
  String tmp = null;
  while ((tmp = br. readline()) != null) {
  System. out. println(tmp);
  }
  int exitValue = p. waitfor();
  ProcessBuilder pb = new ProcessBuilder("wmic", . . . ); pb. redirectErrorStream(true); Process p = pb. start(); BufferedReader br = new BufferedReader(new InputStreamReader(p. getInputStream())); String tmp = null; while ((tmp = br. readline()) != null) { System. out. println(tmp); } int exitValue = p. waitfor();
  编译运行, 发现还是有成绩, 依然还是阻塞。 又google了一下, 大家的评论大多还是关于规范输出和规范错误输出, 那这顺序应该是没有成绩了。 后来在 cmd中敲入wmic的命令, 发现wmic命令敲入以后会进入一个自有的提示符中, 难道是由于规范输入的成绩。 后来又google了一下, 验证了我的猜 想, 果然是由于wmic进程会等候规范输入, 而顺序中没有处置规范输入的地方, 是规范输入阻塞了进程的参加, 修改代码:
  ProcessBuilder pb = new ProcessBuilder("wmic", . . . );
  pb. redirectErrorStream(true);
  Process p = pb. start();
  p.斐格 getOutputStream(). close();
  BufferedReader br = new BufferedReader(new InputStreamReader(p. getInputStream()));
  String tmp = null;
  while ((tmp = br. readline()) != null) {
  System. out. println(tmp);
  }
  int exitValue = p. waitfor();
  ProcessBuilder pb = new ProcessBuilder("wmic", . . . ); pb. redirectErrorStream(true); Process p = pb. start(); p. getOutputStream(). close(); BufferedReader br = new BufferedReader(new InputStreamReader(p. getInputStream())); String tmp = null; while ((tmp = br. readline()) != null) { System. out. println(tmp); } int exitValue = p. waitfor();
  编译运行, 顺序成功执行。 果然是规范输入的缘由。
  后来执行的过程中换了一个效劳的名称, 发现执行失败(可以正常参加, 但是前往的结果是“无效举措”), 但是异样的命令, 在命令行中执行成功, 而且直接适用 Runtime. exec()方法中写入整个命令也可以执行成功, 难道是ProcessBuilder的错误, ProcessBuilder构造函数有两 个:
  ProcessBuilder(List command)
  应用指定的操作系统顺序和参数构造一个进程生成器。
  ProcessBuilder(String. . .  command)
  应用指定的操作系统顺序和参数构造一个进程生成器。
  找到ProcessBuilder的源代码, 发现了对List的解析方法:JDK将List中的所有字符串用空格衔接, 对 list中的每个字符串JDK先判断串中能否包括空格, 如果包括空格, 用双引号将该字符串引起来, 再拼到前面字符串的前面(应该是为了处置路径中包括空格 的成绩), 可恰恰Wmic命令的参数中有一段是name="ServiceName", 如果ServiceName中包换空格, JDK就会把 name="service name"的外层加一个双引号, 招致wmic不能解析该命令了。
  成绩终于全都处置了, 耗费了多半天的时间, 不过收获总是有的, 这里总结一下, 在使用Java调用外部命令的时分, 一定要留意对规范输出、规范输入和错误输 出的处置。 对于一般的命令, 只需求将规范输出和错误输出合并, 一起读出来或者在另外的线程中读出来, 而对于一些特殊的命令, 还有处置规范输入。 建议即使不 使用规范输入, 先close了, 总是不会出错了。 另外, 使用ProcessBuilder时要留意它的空格处置方式能否是你想要的, 如果不是, 就不能用 ProcessBuilder了, 直接使用Runtime. exec()就好了。
jiyizhen-buy.com颈椎保健枕太空记忆枕 igerl.com歌瑞尔内衣

TOP

发新话题