- import java.io.InputStream;
- import java.util.ArrayList;
- public class JavaExcCommand {
- private static String INPUT_STREAM = "INPUTSTREAM";
- private static String ERROR_STREAM = "ERRORSTREAM";
- /**
- * 返回命令执行结果信息串
- * @param command 要执行的命令
- * @return 第一个为标准信息,第二个为错误信息,如果不存在则相应为空
- * @throws Throwable String[]
- */
- public static String[] exec(String command) throws Throwable {
- Process process = null;
- Runtime runtime = Runtime.getRuntime();
- String osName = System.getProperty("os.name").toLowerCase();
- if (osName.indexOf("windows 9") > -1) {
- process = runtime.exec("command.com /c " + command);
- } else if ((osName.indexOf("nt") > -1)
- || (osName.indexOf("windows 20") > -1)
- || (osName.indexOf("windows xp") > -1 || (osName.indexOf("windows vista") > -1))) {
- /*
- * 开关/C指明后面跟随的字符串是命令,并在执行命令后关闭DOS窗口,使用cmd /?查看帮助
- */
- process = runtime.exec("cmd.exe /c " + command);
- } else {
- // Linux,Unix
- process = runtime.exec(command);
- }
- //存储返回结果,第一个为标准信息,第二个为错误信息
- String result[] = new String[2];
- Object mutexInstream = new Object();
- Object mutexErrorstream = new Object();
- new ReadThread(process.getInputStream(), INPUT_STREAM, result, mutexInstream)
- .start();
- new ReadThread(process.getErrorStream(), ERROR_STREAM, result, mutexErrorstream)
- .start();
- //确保子线程已启动
- Thread.sleep(20);
- /*
- * 这里一定要等标准流与错误都读完了后才能继续执行后面的代码,否则外面引用返回的结果可能
- * 为null或空串,所以要等两个线程执行完,这里确保读取的结果已返回。在读取时使用了两个线
- * 程,因为发现在一个线程里读这种流时,有时会阻塞,比如代码实现时先读取标准流,而运行时
- * 命令却执行失败,这时读标准流的动作会阻塞,导致程序最终挂起,先读错误流时如果执行时成
- * 功,这时又可能挂起。还有一个问题就是即使使用两个线程分别读取流,如果不使用同步锁时,也
- * 会有问题:主线程读不到子线程返回的数据,这主要是由于主线读取时子线还没未返回读取到的信
- * 息,又因为两个读线程不能互斥,但又要与主线程同步,所以使用了两个同步锁,这样两个线程谁
- * 先执行互不影响,而且主线程阻塞直到标准信息与错误信息都返回为止
- */
- synchronized (mutexInstream) {
- synchronized (mutexErrorstream) {
- /*
- * 导致当前线程等待,如果必要,一直要等到由该 Process 对象表示的进程已经终止
- * 。如果已终止该子进程,此方法立即返回。如果没有终止该子进程,调用的线程将被
- * 阻塞,直到退出子进程。
- * process.waitFor()目的是等待子进程完成后再往下执行,不过这里好像没有什么
- * 太大的作用除了用来判断返回的状态码外,因为如果程序进到这里表示子线程已执行完
- * 毕,process子进程理所当然的也已执行完毕,如果子进程process未执行完,我想
- * 读流的操作肯定会阻塞的。
- *
- * 另外,使用process.waitFor()要注的是一定不要在数据流读取前使用,否则线程
- * 也会挂起,导致该现象的原因可能是该命令的输内容出比较多,而运行窗口的输出缓冲
- * 区不够大,最后没不能写缓冲引起,所以这里先使用了两个单独的线程去读,这样不管
- * 数据量有多大,都不会阻塞了。
- */
- if (process.waitFor() != 0) {
- result[0] = null;
- } else {
- result[1] = null;
- }
- }
- }
- return result;
- }
- public static void main(String args[]) throws Throwable {
- if (args.length == 0) {
- System.out.println("Useage: \r\n java JavaExcCommand <command>");
- return;
- }
- String[] result = JavaExcCommand.exec(args[0]);
- System.out.println("error info:---------------\r\n" + result[1]);
- System.out.println("std info:-----------------\r\n" + result[0]);
- }
- /*
- * 标准流与错误流读取线程
- */
- private static class ReadThread extends Thread {
- private InputStream is;
- private String[] resultArr;
- private String type;
- private Object mutex;
- public ReadThread(InputStream is, String type, String[] resultArr, Object mutex) {
- this.is = is;
- this.type = type;
- this.resultArr = resultArr;
- this.mutex = mutex;
- }
- public void run() {
- synchronized (mutex) {
- try {
- int readInt = is.read();
- ArrayList result = new ArrayList();
- /*
- * 这里读取时我们不要使用字符流与缓冲流,发现执行某些命令时会阻塞,不
- * 知道是什么原因。所有这里使用了最原始的流来操作,就不会出现问题。
- */
- while (readInt != -1) {
- result.add(Byte.valueOf(String.valueOf((byte) readInt)));
- readInt = is.read();
- }
- byte[] byteArr = new byte[result.size()];
- for (int i = 0; i < result.size(); i++) {
- byteArr[i] = ((Byte) result.get(i)).byteValue();
- }
- if (ERROR_STREAM.equals(this.type)) {
- resultArr[1] = new String(byteArr);
- } else {
- resultArr[0] = new String(byteArr);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
比如传递一个参数为 dir/w ,运行结果如下:
error info:---------------
null
std info:-----------------
驱动器 E 中的卷是 Work
卷的序列号是 9876-AE7E
E:\_\Test 的目录
[.] [..] .classpath .project [bin] [lib]
[src]
2 个文件 904 字节
5 个目录 5,636,612,096 可用字节
如果传一个不存在的命令 aaa ,结果如下:
error info:---------------
'aaa' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
std info:-----------------
null
最后来一个查看操作系统的环境变量,注,这里不是使用的System.getXX来获取的,这是Java虚拟机设置的,我们这里是操作系统所设环境变量,如在window上输出 set ,或在 linux 上输入 env ,window上运行的结果如下:
error info:---------------
null
std info:-----------------
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\jiangzhengjun\AppData\Roaming
classpath=D:\java\jdk1.5.0_17/lib;.
CommonProgramFiles=C:\Program Files\Common Files
COMPUTERNAME=JZJ-PC
ComSpec=C:\Windows\system32\cmd.exe
FP_NO_HOST_CHECK=NO
HOMEDRIVE=C:
HOMEPATH=\Users\jiangzhengjun
java_home=D:\java\jdk1.5.0_17
LOCALAPPDATA=C:\Users\jiangzhengjun\AppData\Local
LOGONSERVER=\\JZJ-PC
NUMBER_OF_PROCESSORS=2
OS=Windows_NT
Path=D:\java\jdk1.5.0_17/bin\..\jre\bin\client;D:\java\jdk1.5.0_17/bin\..\jre\bin;D:\java\jdk1.5.0_17/bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Common Files\Thunder Network\KanKan\Codecs;C:\Program Files\Broadcom\Broadcom 802.11\Driver
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 23 Stepping 6, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=1706
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files
PROMPT=$P$G
PSModulePath=C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
PUBLIC=C:\Users\Public
SESSIONNAME=Console
SystemDrive=C:
SystemRoot=C:\Windows
TEMP=C:\Users\JIANGZ~1\AppData\Local\Temp
TMP=C:\Users\JIANGZ~1\AppData\Local\Temp
USERDOMAIN=jzj-pc
USERNAME=jiangzhengjun
USERPROFILE=C:\Users\jiangzhengjun
windir=C:\Windows
今天作项目时发现了一个简洁一点的办法:
- import java.io.InputStream;
- import java.util.ArrayList;
- public class JavaExcCommand {
- /**
- * 返回命令执行结果信息串
- *
- * @param command
- * 要执行的命令
- * @return 第一个为标准信息,第二个为错误信息
- * @throws Throwable
- * String[]
- */
- public static String[] exec(String command) throws Throwable {
- Process process = null;
- Runtime runtime = Runtime.getRuntime();
- // Linux,Unix
- process = runtime.exec(command);
- // 存储返回结果,第一个为标准信息,第二个为错误信息
- String result[] = new String[2];
- ReadThread inputReadThread = new ReadThread(process.getInputStream());
- ReadThread errReadThread = new ReadThread(process.getErrorStream());
- inputReadThread.start();
- errReadThread.start();
- //确保标准与错误流都读完时才向外界返回执行结果
- while (true) {
- if (inputReadThread.flag && errReadThread.flag) {
- break;
- } else {
- Thread.sleep(1000);
- }
- }
- result[0] = inputReadThread.getResult();
- result[1] = errReadThread.getResult();
- return result;
- }
- public static void main(String args[]) throws Throwable {
- if (args.length == 0) {
- System.out.println("Useage: \r\n java JavaExcCommand <command>");
- return;
- }
- String[] result = JavaExcCommand.exec(args[0]);
- System.out.println("error info:---------------\r\n" + result[1]);
- System.out.println("std info:-----------------\r\n" + result[0]);
- }
- /*
- * 标准流与错误流读取线程
- */
- private static class ReadThread extends Thread {
- private InputStream is;
- private ArrayList result = new ArrayList();
- public boolean flag;// 流是否读取完毕
- public ReadThread(InputStream is) {
- this.is = is;
- }
- // 获取命令执行后输出信息,如果没有则返回空""字符串
- protected String getResult() {
- byte[] byteArr = new byte[result.size()];
- for (int i = 0; i < result.size(); i++) {
- byteArr[i] = ((Byte) result.get(i)).byteValue();
- }
- return new String(byteArr);
- }
- public void run() {
- try {
- int readInt = is.read();
- while (readInt != -1) {
- result.add(Byte.valueOf(String.valueOf((byte) readInt)));
- readInt = is.read();
- }
- flag = true;// 流已读完
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }