提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
Process
背景
- 在编写Java程序时,有时候需要在Java程序中执行另外一个程序。
- 在项目开发中,经常会遇到调用其它程序功能的业务需求
Process是一个抽象类 , 封装了一个进程(即一个执行程序)。
创建进程两种方式
方式1
Runtime runtime = Runtime.getRuntime();
Process p = runtime.exec(cmd);
方式2
Process p = new ProcessBuilder(cmd).start();
其中:
cmd 是命令行,是一个字符串或者是字符串数组。
- 不管在哪种操作系统下,程序具有基本类似的一些属性。一个程序启动后就是程序操作系统的一个进程,进程在执行的时候有自己的环境变量、工作目录。
- 能够在Java中执行的外部程序,必须是一个实际存在的可执行文件,对于cmd/shell下的内嵌命令是不能直接执行的,
1. 采用Runtime的exec执行程序时
- 首先要使用java.lang.Runtime#getRuntime得到一个Runtime实例,然后调用Runtime的exec方法,该方法执行后返回一个Process实例,代表所执行的程序。
- Runtime提供了多个重载的exec方法,其余的方法都是调用如下核心方法实现的:
- cmdarray:包含要调用的命令及其参数的数组。
- envp:环境变量,其中每个元素的环境变量设置格式为name = value,如果子进程应该继承当前进程的环境,则为null。
- dir:子进程的工作目录,如果子进程应该继承当前进程的工作目录,则为null。
2. 采用ProcessBuilder类启动一个新的程序
process类: api 方法
1.destroy()
杀掉子进程。
public abstract void destroy();
public java.lang.Process destroyForcibly() {
destroy();
return this;
}
2.isAlive()
判断子进程是否存活
3.exitValue()
返回子进程退出的值
- 只有启动的进程执行完成、或者由于异常退出后,exitValue方法才会有正常的返回值,否则抛出异常。
4.getOutputStream(),
连接到子进程的输出流
5.getInputStream()
连接到子进程的输入流
6.getErrorStream ()
连接到子进程的错误流
- 获取子进程的错误输出流。如果错误输出被重定向,则不能从该流中读取错误输出。
public abstract OutputStream getOutputStream();
public abstract InputStream getInputStream();
public abstract InputStream getErrorStream();
7.waitFor()
导致当前线程等待
- 导致当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。通过该类提供的方法,可以实现与启动的进程之间通信,达到交互的目的。
- 使当前线程等待,直到子进程退出或者超时
public abstract int waitFor() throws InterruptedException;
public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException{
long startTime = System.nanoTime();
long rem = unit.toNanos(timeout);
do {
try {
exitValue();
return true;
} catch(IllegalThreadStateException ex) {
if (rem > 0)
Thread.sleep(
Math.min(TimeUnit.NANOSECONDS.toMillis(rem) + 1, 100));
}
rem = unit.toNanos(timeout) - (System.nanoTime() - startTime);
} while (rem > 0);
return false;
}
Process 应用案例
1. 从标准输出和错误输出流读取信息
- 从启动其他进程的Java进程看,已启动的其他进程的输出就是一个普通的输入流,可以通过getInputStream和getErrorStream来获取。
- 对于一般输出文本的进程来说,可以将InputStream封装成BufferedReader,然后就可以一行一行的对进程的标准输出进行处理。
通过Runtime实现
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
class ProcessTest1 {
public static void main(String[] args) {
try {
String line = null;
Process p = Runtime.getRuntime().exec("CMD.exe /C dir", null, new File("C:\\"));
BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream(), "GBK"));
while ((line = stdout.readLine()) != null) {
System.out.println(line);
}
stdout.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class test01 {
public static void main(String[] args) {
try {
String line = null;
Process p = Runtime.getRuntime().exec("CMD.exe /C echo %NAME%", new String[]{"NAME=TEST!!!!"});
BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = stdout.readLine()) != null) {
System.out.println(line);
}
stdout.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
通过ProcessBuilder实现
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class ProcessTest2 {
public static void main(String[] args) {
try {
String line = null;
BufferedReader stdout = null;
List list = new ArrayList();
list.add("CMD.EXE");
list.add("/C");
list.add("dir");
ProcessBuilder pb = new ProcessBuilder(list);
pb.directory(new File("C:\\"));
Process p = pb.start();
stdout = new BufferedReader(new InputStreamReader(p.getInputStream(),"GBK"));
while ((line = stdout.readLine()) != null) {
System.out.println(line);
}
stdout.close();
pb = new ProcessBuilder();
pb.command(new String[]{"CMD.exe", "/C", "echo %NAME%"});
pb.environment().put("NAME", "TEST");
p = pb.start();
stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = stdout.readLine()) != null) {
System.out.println(line);
}
stdout.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.获取进程的返回值
通常,一个程序/进程在执行结束后会向操作系统返回一个整数值,0一般代表执行成功,非0表示执行出现问题。
有两种方式可以用来获取进程的返回值:
- 一是利用waitFor(),该方法是阻塞的,直到进程执行完成后再返回。该方法返回一个代表进程返回值的整数值;
- 另一个方法是调用exitValue()方法,该方法是非阻塞的,调用立即返回。但是如果进程没有执行完成,则抛出异常。
3.执行shell中的命令示例
案例1:
业务需求:
- 我需要在linux下首先将一个文件copy到指定的文件夹下面,之后需要将该文件夹下面的文件加入指定的jar中
- 那么问题就来了,必须保证其先后顺序,也就书说再执行第二个命令的时候第一个命令必须完成。
但是结果是新生成的jar中压根没有新加入的文件,但是文件确实copy到了指定的文件夹中,也就是谁两个命令都执行了,问题的关键就是“异步”,这时候需要waitFor()的介入
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class test01 {
public static void main(String[] args){
String source ="/approot1/recive";
String target="/approot1/temp";
String file="/approot1/temp/xx.bin'";
String jar="XXXX";
String copy="cp -rf "+source+" "+target;
String jar="jar -uvf "+jar+" "+file;
cmd(copy);
cmd(jar);
}
public static void cmd(String cmd){
try {
Process ps= Runtime.getRuntime().exec(cmd);
ps.waitFor();
} catch (Exception e) {
}
}
}
案例2:
是无法直接执行shell中的命令的,如果直接执行ls /home命令会报‘java.io.IOException: Cannot run program “ls /home”: error=2, No such file or directory’的错误,参见如下代码示例。
public class ProcessTest3 {
public static void main(String[] args) {
try {
String line;
ProcessBuilder pb = new ProcessBuilder();
pb.command("bash", "-c", "ls /home");
pb.redirectErrorStream(true);
Process p = pb.start();
BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = stdout.readLine()) != null) {
System.out.println(line);
}
int ret = p.waitFor();
System.out.println("the return code is " + ret);
stdout.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
案例3:
public static void restart() throws IOException {
Process p;
String cmd = "c:\\test\\test.bat";
try {
p = Runtime.getRuntime().exec(cmd);
InputStream fis = p.getInputStream();
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
案例4:
public static void restart() throws IOException {
try {
ProcessBuilder pb = new ProcessBuilder("java", "-jar", "Test3.jar");
pb.directory(new File("F:\\dist"));
Map<String, String> map = pb.environment();
Process p1 = pb.start();
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
}
}
|