java使用Runtime.getRuntime().exec调用外部程序
目录
- 概述
- 方法API
- 程序阻塞问题
- 实例
- 拓展
概述
Runtime.getRuntime().exec 用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。功能和Windows“运行”类似。
格式:
Process process = Runtime.getRuntime().exec( ".//p.exe "); process.waitfor();
第一行的“.//p.exe”是要执行的程序名,Runtime.getRuntime() 返回当前应用程序的Runtime对象,该对象的 exec() 方法指示Java虚拟机创建一个子进程执行指定的可执行程序,并返回与该子进程对应的Process对象实例。通过Process可以控制该子进程的执行或获取该子进程的信息。
第二条语句的目的等待子进程完成再往下执行。
方法API
Runtime.getRuntime().exec共有六个重载方法:
// 在单独的进程中执行指定的外部可执行程序的启动路径或字符串命令 public Process exec(String command) // 在单独的进程中执行指定命令和变量 public Process exec(St编程客栈ring[] cmdArray) // 在指定环境的独立进程中执行指定命令和变量 public Process exec(String command, String[] envp) // 在指定环境的独立进程中执行指定的命令和变量 public Process exec(String[] cmdArray, String[] envp) // 在指定环境和工作目录的独立进程中执行指定的字符串命令 public Process exec(String command, String[] envp, File dir) // 在指定环境和工作目录的独立进程中执行指定的命令和变量 public Process exec(String[] cmdarray, String[] envp, File dir) // 参数说明: cmdarray // 包含所调用命令及其参数的数组。数组第一个元素是命令,其余是参数 envp // 字符串数组,其中每个元素的环境变量的设置格式为 name=value,如果子进程应该继承当前进程的环境,则该参数为null dir // 子进程的工作目录;如果子进程应该继承当前进程的工作目录,则该参数为null // 参数cmdArray 示例:shutdown -s -t 3600 String arr[] = {"shutdown","-s","-t","3600"}; Process process = Runtime.getRuntime().exec(arr[]); /* 注意: 在调用这个方法时,不能将命令和参数放在一起,eg:String arr[] = {"shutdown -s -t 3600"}; 这样会导致程序把“shutdown -s -t 3600”当成是一条命令的名称,然后去查找“shutdown -s -t 3600”这条命令,它当然会找不到,所以就会报错 */
注意:
Runtime.exec() 不是cmd或shell环境,因此无法直接调用dir等命令,需要在程序中读取运行的操作系统平台,以调用不同的命令解释器(NT:cmd.exe,windows 95/98:command.exe,linux:/bin/sh)
Procss类将持有该程序返回 Java VM 的引用。这个procss类是一个抽象类,具体子类的实现依赖于不同的底层操作系统。
Process 的常用方法:
// 导致当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。 int waihttp://www.devze.comtFor() /* 如果已终止该子进程,此方法立即返回。 如果没有终止该子进程,调用的线程将被阻塞,直到退出子进程,0 表示正常终止 */ // 杀掉子进程 void destroy() // 返回子进程的出口值,值 0 表示正常终止 int exitValue() // 获取子进程的错误流 InputStream getErrorStream() // 获取子进程的输入流 InputStream getInputStream() // 获取子进程的输出流 OutputStream getOutputStream()
程序阻塞问题
通过 Process实例.getInputStream() 和 Process实例.getErrorStream() 获取的输入流和错误信息流python是缓冲池向当前Java程序提供的,而不是直接获取外部程序的标准输出流和标准错误流。
而缓冲池的容量是一定的,因此若外部程序在运行过程中不断向缓冲池输出内容,当缓冲池填满,那么外部程序将暂停运行直到缓冲池有空位可接收外部程序的输出内容为止。(采用xcopy命令复制大量文件时将会出现该问题)
解决办法:当前的Java程序不断读取缓冲池的内容,从而为腾出缓冲池的空间。
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” 表示当命令执行完成后关闭自身。
实例
在当前目录执行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 eandroid){ e.printStackTrace(); }
执行代码后查看c:\dir.txt文件内容如如下:
驱动器 D 中的卷没有标签。
卷的序列号是 8074-B214 D:\test 的目录 2014/09/22 14:45 <DIR> movies2014/03/31 17:14 8,642 readme.txt
拓展
1,调用一次exec方法执行多条cmd命令,使用 && 分隔命令,该方法的局限性是只能在cmd里面使用
Runtime.getRuntime().exec("cmd /c set CLASSPATH=D:\\ && javac D:\\a.java && java a");
// 方法重载:public Process exec(String[] cmdarray, String[] envp, File dir) String arr[] = {"CLASSPATH=D://","Path=C:\\Program Files\\Java\\jdk1.8.0_131\\bin"}; Runtime.getRuntime().exec("cmd /c javac a.java && java a", arr, new File("D://"));
2.执行Runtime.exec()需要注意的陷阱
作为Java语言的一部分。java.lang包被隐藏的导入到每一个Java程序。这个包的表面陷阱,经常影响到大多数程序员。这个月,我将讨论运行时exec()方法时的潜伏陷阱。
1.当运行exec()时不会执行命令
java.lang.Runtime类,突出了静态方法calledgetRuntime(),,它会检索当前的Java运行时环境。这是唯一的方法来获取Runtime对象的引用。获取该引用,您通过可以调用Runtime类的exec()方法运行外部程序。开发人员经常调用这个方法来启动浏览器显示一个html帮助页面。
exec()有四个重载:
public Process exec(String command); public Process exec(String [] cmdArray); public Process exec(String command, String [] envp); public Process exec(String [] cmdArray, String [] envp);
对于每个这样的方法,都会产生一个命令,并可能携带一组参数——被传递给一个特定操作系统的函数调用。这随后创建一个特定操作系统的进程(一个运行着的程序),procss类将持有该程序返回Java VM的引用。这个procss类是一个抽象类,具体子类的实现依赖于不同的底层操作系统。
你可以通过三种可能的输入参数到这些方法:
1、一个字符串,表示程序执行和程序的任何参数。
2、一个字符串数组,通过参数来区分出程序的实现功能。
3、一个环境变量的数组
传递环境变量是,使用格式化的方式:名称=值。如果你使用单个字符串和它的参数的方式调用exec()的重载,,注意字符串是通过StringTokenizer类被解析,使用空格作为分隔符。
2.陷入 IllegalThreadStateException
运行exec()的第一个陷阱,是theIllegalThreadStateException。 普遍上,第一次对api的尝试,都是基于一些最常用的方法。例如,执行一个java vm的外部过程,编程客栈我们使用exec()方法。查看外部过程的返回值,我们使用process类的exitValue()方法。看到的值外部过程的回报,我们使用exitValue()方法在过程类。在我们的第一个示例中,我们将尝试执行Java编译器(javac exe)。
清单 4.1 BadExecJavac.java
import java.util.*; import java.io.*; public class BadExecJavac { public static void main(String args[])
到此这篇关于java使用Runtime.getRuntime().exec调用外部程序的文章就介绍到这了,更多相关java调用外部程序内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论