Java Runtime 执行系统命令行程序

以前写过一篇文章,介绍通过 Java 的 Runtime 类执行操作系统命令行程序:Java调用linux系统shell执行命令。最近项目中又有需要用这个方法,在使用过程中遇到了一些新的问题,感觉以前没有弄清楚,故在此做补充学习记录。

先说明一下这次的需求,在 Java 程序中控制 Hadoop 命令执行 MapReduce 作业,并获取其输出内容。本来没有什么特殊,但由于 MR 执行的是 Kmeans 算法,会产递归产生多个 MR 程序,在捕获输出的时候就只有简单的几句提示,没有 MR 作业的详细信息。

经过查询后发现,执行过程中有一部分信息是作为普通信息输出的,另一部分则是作为 debug 信息输出的。如下图,用红线圈出来一行为普通输出(开始捕获到的只有这一行),其它均为 debug 信息。

为了区别这两种信息,这里就要说一下 Runtime 这个东西了。 Java API 中对该类的解释是 public class java.lang.Runtime extends java.lang.Object。

每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。应用程序不能创建自己的 Runtime 类实例。在API 文档 可以看到,执行过一个命令后,系统会返回一个新的
Process 对象,用于管理子进程。那么,这个新的 Process 对象又是何许东东,继续来看 API ,public abstract class java.lang.Process extends java.lang.Object。该实例可用来控制进程并获得相关信息。

并且,Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法。

它的所有标准 io(即 stdin、stdout 和 stderr)操作都将通过三个流 (getOutputStream()、getInputStream() 和 getErrorStream()) 重定向到父进程。

父进程使用这些流来提供到子进程的输入和获得从子进程的输出。因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁。

现在问题就明显了。以前只获取了 Process.getInputStream() 的 InputStream 对象,没有用 process.getErrorStream() 获取进程的错误输出流传送的数据。

本来是想通过 while 循环来输出两个流的数据,但是发现在利用 BufferedReader 读取 Process stream 流的时候,当使 stream 为空(还没产生,并不是 null ),那么 BufferedReader 则会被阻塞。

所以想了一下还是得用多线程的方式同时输出两个流的内容。

那么,代码更新一下,变成如下的方式。

package com.cz.shell;

import java.io.BufferedReader;
import java.io.InputStreamReader;

class CzStreamOutput extends Thread {
	public BufferedReader br;

	public CzStreamOutput() {
	}

	public CzStreamOutput(BufferedReader br) {
		this.br = br;
	}

	public void run() {
		String line;
		try {
			while ((line = br.readLine()) != null) {
				System.out.println(line);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

public class CzShell {
	public static void runShell(String cmd) throws Exception {
		Process process = null;
		try {
			process = Runtime.getRuntime().exec(cmd);
			BufferedReader bri = new BufferedReader(new InputStreamReader(process.getInputStream()));
			BufferedReader bre = new BufferedReader(new InputStreamReader(process.getErrorStream()));
			new CzStreamOutput(bri).start();
			new CzStreamOutput(bre).start();
			process.waitFor();
			bri.close();
			bre.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			process.destroy();
		}
	}
}

在 Linux (Centos 6.2)上运行测试,一切顺利。不过在此说明一下,由于是多线程,理论上会出现一些错误流和输出流顺序颠倒的情况,但是对于多数命令来说,系统的始终频率要比命令执行时两个流的间隔高很多,出现混乱的可能性极小。

Java Runtime 执行系统命令行程序

时间: 2024-08-18 21:00:01

Java Runtime 执行系统命令行程序的相关文章

Esper调用Java代码执行系统命令

Esper语言是可以调用高级语言的静态方法的: 以调用Java的静态方法执行系统命令为例: select Runtime.getRuntime().exec(\"calc\"),avg(price) from " + product + ".win:length_batch(3) 完整代码可以参考如下链接: http://blog.csdn.net/luonanqin/article/details/9900295

java中执行系统命令

java程序中执行系统命令猛击下面的链接看看你就知道怎么用了 http://blog.csdn.net/a19881029/article/details/8063758 http://wuhongyu.iteye.com/blog/461477/ http://www.blogjava.net/fastzch/archive/2008/07/08/213477.html

使用java对执行命令行 或 执行bat文件

public class Hellotianhao { public static void main(String[] args) throws Exception{ System.out.println("hello tianhao"); Runtime.getRuntime().exec("cmd /k mkdir d:\\xutianhao"); } } 运行结果是在d盘新建了一个名为xutianhao的文件夹 java执行bat文件  bat文件书写注意在

Go语言执行系统命令行命令(转)

1 package main 2 3 import ( 4 "os" 5 "os/exec" 6 "fmt" 7 "flag" 8 "strings" 9 ) 10 11 func main() { 12 command := flag.String("cmd", "pwd", "Set the command.") 13 args := flag

[Java][Android][Process] 暴力的服务可以解决一切,暴力的方式执行命令行语句

无论是在Java或者Android中执行命令行语句殊途同归都是创建一个子进程执行调用可执行文件执行命令,类似于Windows中的CMD一样. 此时你有两种方式执行:ProcessBuilder与Runtime:两种创建方式各有千秋,至于区别详见:[Java][Android][Process] ProcessBuilder与Runtime区别 在Android中创建子进程执行命令的时候有着一定的限制: 1.JVM提供的内存有限. 2.底层缓冲区间大小有限. 3.在高并发情况下容易造成阻塞. 基于

利用java开发一个双击执行的小程序

之前我们利用java写了很多东西,但是好像都没有什么实际意义. 因为有意义桌面小程序怎么都得有个界面,可是界面又不太好搞.或者 了解到这一层的人就少之又少了. 呀,是不是还得开辟一些版面来介绍awt和 swing... 算了 先把这个 双击执行的小程序 贡献出来. 这次 在分享一下源代码[以前还没有上传过源代码,布置怎么个搞法] 要求是: 输入一个 后缀名,然后输入所在目录,然后 点击查找,比如我们可以 输入F:\,然后查找 F盘下面的所有后缀名为比如.pdf 举例: 主要是 看了很多 资源,然

Java命令行程序构建工具-airline

以前对于开发Java命令行程序,我都是很头大的,命令行程序麻烦的是解析参数,以及一些帮助信息,今天在研究接口测试时偶然发现了一个工具可以让你快速构建命令行程序 github地址 airline 导入jar包 airline jar 在maven仓库里搜索适合你构建系统的语句 代码 我找了个解析har文件的项目,来讲解开发过程 定制自己的命令行 我的命令行以doctorq作为命令,参数为company,命令的完整格式应该为doctorq company XXXXX. @Command(name="

[Android] [Java] 分享 Process 执行命令行封装类

在上一篇文章中提到,利用Java创建进程执行命令行语句创建过多后会出现无法创建进程的问题. [Android] ProcessBuilder与Runtime.getRuntime().exec分别创建进程的区别 进行多次测试后发现是因为没有正常退出进程,以及完全读取掉流数据,和关闭流导致的问题. 在多次优化后,建立如下封装类: ProcessModel.java import java.io.BufferedReader; import java.io.IOException; import j

Java Runtime.getRuntime().exec 执行带空格命令解决办法

String command = OpenOffice_HOME + "program\\soffice -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;\" -nofirststartwizard "; command = "cmd /c start "+command.replaceAll(" ","\" \""); P