`

使用JAVA调用操作系统命令

    博客分类:
  • Java
阅读更多
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();
			}
		}
	}

}

 

分享到:
评论

相关推荐

    java调用shell命令.pdf

    在 Java 中调用 Shell 命令是非常常见的操作,特别是在需要执行系统命令或脚本时。在这个例子中,我们将看到如何使用 Java 调用 Shell 命令,并介绍相关的知识点。 Java 调用 Shell 命令的必要性 在实际开发中,...

    java系统命令调用

    本文将详细介绍如何使用Java Runtime类中的`getRuntime().exec()`方法来调用系统命令,并提供一些实际应用场景的例子。 ### Java Runtime.getRuntime().exec() `java.lang.Runtime`类提供了运行时系统的表示形式,...

    java调用操作系统命令(远程,本地都有)

    java调用操作系统命令源码工具类,包含远程输入用户名和密码方式及本地调用,同时兼容处理了Windows及Linux命令和执行结果的返回。使用者可以通过工具类方法直接调用,传入操作系统的命令即可执行,方法返回操作结果...

    java调用windows命令

    以下是如何使用Java调用Windows命令行的详细步骤和注意事项: 1. **调用外部程序** - 使用`Runtime.getRuntime().exec()`方法创建一个子进程来执行指定的可执行程序。例如: ```java Process process = Runtime....

    在Linux系统下用java执行系统命令实例讲解

    在Linux系统下,Java编程语言提供了丰富的API来执行操作系统级别的命令。这主要通过`java.lang.Runtime`类和`java.lang.ProcessBuilder`类实现。本文将深入讲解如何在Java程序中调用Linux命令,并通过实例来阐述这一...

    java 调用doc命令

    Java调用doc命令主要涉及到的是Java的进程...总的来说,Java调用doc命令涉及了Java与操作系统交互的能力,这在系统集成、自动化测试或文件处理场景中非常常见。正确理解和使用这些技术能够帮助你构建更强大的Java应用。

    java执行系统命令

    在Java中执行系统命令是一种常见的需求,尤其是在需要与操作系统进行交互的应用场景中。本文将详细介绍如何使用Java来执行系统命令,并给出具体的示例代码,特别是针对Linux系统的操作。 #### 二、基本原理 在Java...

    java实现重启操作系统

    总结来说,Java实现重启操作系统是通过调用操作系统命令完成的,这需要对操作系统命令有深入理解,并且需要注意权限管理和异常处理。同时,这也是Java跨平台特性的体现,能够在不同操作系统环境下执行相同的功能。

    java调用DOS命令

    Java调用DOS命令是指在Java程序中执行操作系统级别的命令,比如Windows下的CMD命令或Linux下的Shell命令。这种功能在很多场景下都很有用,比如自动化脚本、文件操作、系统管理等。Java提供了Runtime类和...

    java工程 实现调用系统命令ping

    总结,Java调用系统命令“ping”涉及到对操作系统接口的使用,以及对输入/输出流的处理。在Spring框架下,我们可以通过依赖注入简化代码并提高可维护性。实践过程中需要注意处理可能的异常,并确保正确关闭所有打开...

    Java调用Linux命令

    ### Java调用Linux命令 Java提供了一种强大的机制来执行操作系统级别的任务,其中包括调用Linux命令。实现这一功能的核心是`Runtime`类中的`exec()`方法。这个方法允许Java应用程序创建一个新的进程来执行指定的...

    java调用linuex命令

    本文将详细探讨如何利用Java调用Linux命令,这一技能对于任何希望在Java应用中集成Linux功能的开发者来说都是至关重要的。 ### Java调用Linux命令的方法 Java提供了多种方式来执行外部命令或脚本,其中最常用的是...

    java 调用 windows cmd 命令

    总结,通过Java调用Windows CMD命令,我们可以方便地执行系统级任务,实现与操作系统的交互。`FileProcessInShell.java`可能就是这样一个例子,它演示了如何在Java程序中执行和处理CMD命令的输出。在实际开发中,...

    JAVA如何调用DOS命令.doc

    在Java编程中,有时我们需要在程序中调用操作系统的一些功能,比如执行DOS命令,这通常是通过Java的`Runtime`类和`Process`类来实现的。本文将详细讲解如何在Java中调用DOS命令以及相关的注意事项。 首先,调用DOS...

    Java调用应用程序和Dos中的命令

    在Java编程中,有时候我们需要执行一些操作系统级别的任务,例如启动一个外部程序、执行一些系统命令等。这通常可以通过Java的`Runtime`类实现,尤其是通过`Runtime.exec()`方法来创建一个新的进程。本文将详细介绍...

    java调用dos命令

    总结,通过Java调用DOS命令,我们可以轻松地实现与操作系统的交互,完成如创建文件夹、复制文件、运行批处理文件等任务。这使得Java程序具有更广泛的适用性,能够处理更多系统级别的操作。在实际开发中,要注意处理...

    14-Java操作Linux命令分割合并文本文件1

    2. **Java调用Linux命令** - 在Java中,可以通过`Runtime.getRuntime().exec()`或`ProcessBuilder`类来执行Linux命令。在描述中提到的`getDiskUsage`方法就使用了`ProcessBuilder`来执行`df -hl -P`命令,获取磁盘...

    Java调用相应cmd命令的实例

    在Java编程中,有时我们需要与操作系统进行交互,执行一些系统级别的任务,比如运行命令行(CMD)命令。本文将深入探讨如何在Java中调用相应的CMD命令,通过实例来帮助理解这一过程。 首先,Java提供了`Runtime`类...

    JAVA调用OS命令删除文件

    2. **速度**:某些情况下,调用OS命令可能比Java的File API更快,因为这是直接由操作系统处理的。 然而,这种方式也存在一些缺点: 1. **安全性**:调用OS命令可能会引入安全风险,如果命令被恶意篡改,可能会导致...

    Linux操作系统的常用命令

    Linux 操作系统的常用命令 Linux 操作系统提供了许多实用的命令来帮助用户管理和操作文件、目录、网络等。以下是 Linux 操作系统中的一些常用命令的总结: 文件和目录操作 * ls 命令:用于查看当前目录下的文件和...

Global site tag (gtag.js) - Google Analytics