`

使用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调用操作系统命令(远程,本地都有)

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

    java-虚拟机 操作系统监控工具-源码

    支持操作系统监控:内存状态、CPU负载、磁盘IO及吞吐率、磁盘健康状态、网卡信息、网卡IO 支持Java虚拟机监控:GC信息、内存使用情况、内存池信息、类加载器、线程堆栈 支持生成火焰图(采样事件包括CPU、内存分配、...

    Java 调用 Linux 命令实战(含完整代码)1

    前言我所在项目组刚接到一个 Java 重启 keepalived 需求,具体需求是通过 Java 接口去操作安装在Linux 系统上的 keepalived,根

    操作系统实验 操作系统实验报告 文件管理 进程管理等

    操作系统实验(含实验报告) 1、进程调度 2、作业调度 3、主存空间的分配与回收 4、文件系统 一、 实验目的 用高级语言编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解。 二、实验内容和要求...

    使用JAVA获取客户端MAC地址.doc

    利用Runtime call操作系统的命令,具体的命令取决于不同的操作系统,注意不要调用Runtime.getRuntime().exec(String)接口,要用Runtime.getRuntime().exec(String[])这个接口,不然复杂命令的执行会有问题。...

    操作系统实验报告及源码(JAVA实现).zip

    实验一 处理机调度模拟 用C/C++编写和调试一个进程调度程序,以加深对进程的概念及进程调度算法的理解。...用C/C++编写和调试一个简单的文件系统,模拟文件管理的工作过程,从而对各种文件操作命令的实质

    可直接运行,基于 Java 模拟操作系统

    可直接运行,模拟一个采用多道程序设计方法的单用户操作系统,该操作系统包括进程管理、存储管理、设备管理、文件管理和用户接口四部分。 ① 进程管理部分功能 实现简单的 CPU,包括指令的读取、解析、执行等 实现...

    java实现windows机器系统时间同步网络时间例子

    java类获取网络时间操作cmd命令(打成jar包了,就一个sysTimeTest类,30行代码用反编译工具一看就懂,网上也有很多例子)。然后打成jar包,windows批处理操作,单次同步更新windows系统时间,每天定时同步更新windows...

    基于 Java 模拟操作系统【100011078】

    模拟一个采用多道程序设计方法的单用户操作系统,该操作系统包括进程管理、存储管理、设备管理、文件管理和用户接口四部分。 ① 进程管理部分功能 实现简单的 CPU,包括指令的读取、解析、执行等 实现系统时钟,控制...

    Java出租物业管理系统.zip

    同样,大多数数据是使用 Java 和 MySQL 存储和操作的,因此我们可以轻松地在应用程序的各个阶段之间链接数据表。最后,我们以此应用程序为契机,应用设计原则和模式来构建一个模块化且文档齐全的应用程序,该应用...

    Java开发技术大全(500个源代码).

    getLinePara.java 获取命令行参数示例 hasStaticMethod.java 静态成员方法示例 hasStatMember.java 静态成员变量示例 HelloNative.c 用C写的一个小程序 HelloNative.dll 用C生成的DLL文件 HelloNative.exp 用...

    java开发的企业内部通讯系统

    最重要的是必须适应任何操作系统,也就是实现跨平台技术,因为企业内部的工作需要,工作环境中使用了多个操作系统来完成不同的工作。另外,系统不需要使用服务器中转和记录通讯内容,可以独立完成通讯任务,排除职工...

    JAVA上百实例源码以及开源项目源代码

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    《操作系统原理与设计》全本

    1.1 操作系统的定义和目标 1 1.1.1 OS作为用户与计算机硬件之间的接口 2 1.1.2 OS作为计算机系统的资源管理者 2 1.1.3 OS作为虚拟计算机 2 1.2 操作系统的形成和发展 3 1.2.1 人工操作阶段 3 1.2.2 管理程序阶段 4 ...

    Java简单实现调用命令行并获取执行结果示例

    主要介绍了Java简单实现调用命令行并获取执行结果,结合实例形式分析了Java调用ping命令并获取执行结果相关操作技巧,需要的朋友可以参考下

    基于Java实现Socket通信的远程监控系统【100012520】

    ​ 该系统基于 FTP 服务器修改而成,使用 TCP 协议传送命令,使用 UDP 协议进行文件发送以及视频流的传输。在监控目标机端运行 FileServer.java 即可对其进行监控。 ​ Server 端使用了线程池,最大支持 4 个客户端...

    java开源包8

    JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...

    网络操作系统实训实验报告

    能独立搭建UNIX操作系统,掌握OpenSolaris的安装、运行和使用。 2. 使用自己的账号登录UNIX 系统, 用户名为:学号和姓名汉语拼音全拼。在用户主目录下,新建子目录,子目录名为:专业和班级(可以是拼音)。 3. 在...

    操作系统课程设计基于Java实现的仿真Linux系统源码+项目说明文档.zip

    操作系统课程设计基于Java实现的仿真Linux系统源码+项目说明文档.zip 1、该资源内项目代码都是经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信...

    Java程序设计基础:环境变量配置.pptx

    指向Java命令程序所在目录,设置Path后,操作系统识别java编译器、解释器等工具的位置。 ClassPath 类路径环境变量 指定类搜索路径,让Java执行环境识别程序中使用的类库的位置。Java虚拟机就是通过ClassPath来寻找...

Global site tag (gtag.js) - Google Analytics