Java魔法堂:找外援的利器——Runtime.exec详解

一、前言                                

Java虽然五脏俱全但总有软肋,譬如获取CPU等硬件信息,当然我们可以通过JNI调用C/C++来获取,但对于对C/C++和Windows API不熟的码农是一系列复杂的学习和踩坑过程。那能不能通过简单一些、学习成本低一些的方式呢?答案是肯定的,在功能实现放在首位的情况下,借他山之石是最简洁有力的做法。而 Runtime.exec方法 就为我们打开这么的一条路了。

二、认识 java.lang.Runtime.exec方法                     

  作用:用于调用外部程序,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。功能就是和windows的“运行”一样啦。

  方法重载:

exec(String command) ,调用外部程序,入参command为外部可执行程序的启动路径或命令。

exec(String[] cmdArray) ,调用外部程序,入参cmdArray的元素将组合成为一条完整的外部可执行程序的启动路径或命令。

exec(String command, String[] envp) ,在调用外部程序之前设置系统环境变量,该变量仅供command入参使用,envp每个元素为一个系统环境变量,并且字符串格式为“环境变量名=环境变量值”。

exec(String command, String[] envp, File dir) , 除了设置系统环境变量外,还通过入参dir设置当前工作目录。

  实例 —— 在当前目录执行dir命令,并将结果保存到c:\dir.txt文本文件中:

前提:假设当前用户的家目录为c:\user\fsjohnhuang

c:\user\fsjohnhuang下的目录结构

c:\user\fsjohnhuang
|--jottings
|--test.txt

d:\test下的目录结构

d:\test
|--movies
|--readme.txt

代码片段

Runtime r = Runtime.getRuntime();
try{
  Process proc = r.exec("cmd /c dir > %dest%", new String[]{"dest=c:\\dir.txt", new File("d:\\test")});
  int exitVal = proc.waitFor(); // 阻塞当前线程,并等待外部程序中止后获取结果码
  System.out.println(exitVal == 0 ? "成功" : "失败");
}
catch(Exception e){
  e.printStackTrace();
}

执行代码后查看c:\dir.txt文件内容如如下:

驱动器 D 中的卷没有标签。
 卷的序列号是 8074-B214

 D:\test 的目录

2014/09/22  14:45    <DIR>          movies
2014/03/31  17:14             8,642 readme.txt

三、注意点                              

1.  Runtime.exec() 不是cmd或shell环境,因此无法直接调用dir等命令。若要调用命令行下的命令,请参考第2节的实例。

2.  通过 Process实例.getInputStream() 和 Process实例.getErrorStream() 获取的输入流和错误信息流是缓冲池向当前Java程序提供的,而不是直接获取外部程序的标准输出流和标准错误流。

而缓冲池的容量是一定的,因此若外部程序在运行过程中不断向缓冲池输出内容,当缓冲池填满,那么外部程序将暂停运行直到缓冲池有空位可接收外部程序的输出内容为止。(采用xcopy命令复制大量文件时将会出现该问题)

解决办法就是当前的Java程序不断读取缓冲池的内容,从而为腾出缓冲池的空间。

四、绝对是坑                              

为解决第3节第2点注意事项中提及的问题。我们可以通过下列两种方式处理

Runtime r = Runtime.getRuntime();
try{
  Process proc = r.exec("cmd /c dir"); // 假设该操作为造成大量内容输出
  // 采用字符流读取缓冲池内容,腾出空间
  BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream(), "gbk")));
  String line = null;
  while ((line = reader.readLine()) != null){
     System.out.println(line);
  }

  // 或采用字节流读取缓冲池内容,腾出空间
  // ByteArrayOutputStream pool = new ByteArrayOutputStream();
  // byte[] buffer = new byte[1024];
  // int count = -1;
  // while ((count = proc.getInputStream().read(buffer)) != -1){
  //   pool.write(buffer, 0, count);
  //   buffer = new byte[1024];
  // }
  // System.out.println(pool.toString("gbk"));

  int exitVal = proc.waitFor();
  System.out.println(exitVal == 0 ? "成功" : "失败");
}
catch(Exception e){
  e.printStackTrace();
}

这里要注意一个坑:外部程序在执行结束后将会自动关闭,否则不管是字符流还是字节流均由于既读不到数据,又读不到流结束符而出现阻塞Java进程运行的情况。

而 cmd /c 就是告诉cmd环境进程,当执行完成后关闭自身。

五、总结                                  

用适当的工具做适当的事, Runtime.exec方法 让我们功能实现的手段更灵活了!

尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/4081445.html  ^_^肥仔John

六、参考                                  

http://fuliang.iteye.com/blog/574260

时间: 2024-08-01 19:14:31

Java魔法堂:找外援的利器——Runtime.exec详解的相关文章

JS魔法堂:IMG元素加载行为详解

一.前言 在<JS魔法堂:jsDeferred源码剖析>中我们了解到img元素加载失败可以作为函数异步执行的优化方案,本文打算对img元素的加载行为进行更深入的探讨. 二.资源加载的相关属性和事件 资源加载首先当然是确定资源位置的 src属性 .随之就是资源加载成功与否的 onload事件 和 onerror事件 ,对于IE5~10来说还多了一个 onreadystatechage事件 和与该事件相关联的 readyState属性 和 complete属性 . onload事件 ,当资源加载完

Java魔法堂:String.format详解

Java魔法堂:String.format详解   目录     一.前言    二.重载方法     三.占位符     四.对字符.字符串进行格式化     五.对整数进行格式化     六.对浮点数进行格式化     七.对日期时间进行格式化     八.其他转换符  九.总结   参考 一.前言 String.format 作为文本处理工具,为我们提供强大而丰富的字符串格式化功能,为了不止步于简单调用 String.format("Hello %s", "John&q

Java魔法堂:String.format详解 (转载)

Java魔法堂:String.format详解   目录 一.前言 二.重载方法 三.占位符 四.对字符.字符串进行格式化 五.对整数进行格式化 六.对浮点数进行格式化 七.对日期时间进行格式化 八.其他转换符   九.总结   参考 一.前言 String.format 作为文本处理工具,为我们提供强大而丰富的字符串格式化功能,为了不止步于简单调用 String.format("Hello %s", "John"); ,下面将笔记整理并记录下来. 二.重载方法 /

Java魔法堂:类加载器入了个门

一.前言 <Java魔法堂:类加载机制入了个门>中提及整个类加载流程中只有加载阶段作为码农的我们可以入手干预,其余均由JVM处理.本文将记录加载阶段的核心组件——类加载器的相关信息,以便日后查阅.若有纰漏请大家指正,谢谢. 注意:以下内容基于JDK7和HotSpot VM. 二.类加载器种类及其关系 从上图可知Java主要有4种类加载器 1. Bootstrap ClassLoader(引导类加载器):作为JVM的一部分无法在应用程序中直接引用,由C/C++实现(其他JVM可能通过Java来实

【转】Java魔法堂:String.format详解

Java魔法堂:String.format详解   目录     一.前言    二.重载方法     三.占位符     四.对字符.字符串进行格式化     五.对整数进行格式化     六.对浮点数进行格式化     七.对日期时间进行格式化     八.其他转换符  九.总结   参考 一.前言 String.format 作为文本处理工具,为我们提供强大而丰富的字符串格式化功能,为了不止步于简单调用 String.format("Hello %s", "John&q

java中静态代码块的用法 static用法详解

(一)java 静态代码块 静态方法区别一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序来调用的时候,需要使用静态方法,这种代码是被动执行的. 静态方法在类加载的时候 就已经加载 可以用类名直接调用比如main方法就必须是静态的 这是程序入口两者的区别就是:静态代码块是自动执行的;静态方法是被调用的时候才执行的.静态方法(1)在Java里,可以定义一个不需要创建对象的方法,这种方法就是

JAVA环境变量JAVA_HOME、CLASSPATH、PATH设置详解

JAVA环境变量JAVA_HOME.CLASSPATH.PATH设置详解 Windows下JAVA用到的环境变量主要有3个,JAVA_HOME.CLASSPATH.PATH.下面逐个分析. JAVA_HOME 指向的是JDK的安装路径,如C:\jdk1.5.0_06,在这路径下你应该能够找到bin.lib等目录.值得一提的是,JDK的安装路径可以选择任意磁盘目录,不过建议你放的目录层次浅一点,如果你放的目录很深,比如x:\XXXXXX\xxxxx\XXXX\xxxx\XXXX\xxxx\XXXX

java开源框架SpringSide3多数据源配置的方法详解

原创整理不易,转载请注明出处:java开源框架SpringSide3多数据源配置的方法详解 代码下载地址:http://www.zuidaima.com/share/1781579130801152.htm 在SpringSide 3社区中,不断有人提出多数据源配置的问题,但是时至今日却一直没有一个完美的答案.经过一个星期的折腾,我总算搞清楚了在SpringSide 3中配置多数据源的各种困难并加以解决,在这里,特地把我配置SpringSide 3项目中多数据源的过程写出来,与大家分享. 我使用

[转]JAVA环境变量JAVA_HOME、CLASSPATH、PATH设置详解

[转] JAVA环境变量JAVA_HOME.CLASSPATH.PATH设置详解 - dreamman的日志 - 网易博客http://blog.163.com/dreamman_yx/blog/static/26526894200842414338201/ Windows下JAVA用到的环境变量主要有3个,JAVA_HOME.CLASSPATH.PATH.下面逐个分析. JAVA_HOME 指向的是JDK的安装路径,如C:\jdk1.5.0_06,在这路径下你应该能够找到bin.lib等目录.