文章目录提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
- Process
- 背景
- Process是一个抽象类 , 封装了一个进程(即一个执行程序)。
- 创建进程两种方式
- Runtime runtime = Runtime.getRuntime();
- Process p = runtime.exec(cmd);
- Process p = new ProcessBuilder(cmd).start();
- cmd 是命令行,是一个字符串或者是字符串数组。
- 1. 采用Runtime的exec执行程序时
- 2. 采用ProcessBuilder类启动一个新的程序
- API--18--ProcessBuilder
- process类: api 方法
- 1.destroy()
- 杀掉子进程。
- 2.isAlive()
- 判断子进程是否存活
- 3.exitValue()
- 返回子进程退出的值
- 4.getOutputStream(),
- 连接到子进程的输出流
- 5.getInputStream()
- 连接到子进程的输入流
- 6.getErrorStream ()
- 连接到子进程的错误流
- 7.waitFor()
- 导致当前线程等待
- Process 应用案例
- 1. 从标准输出和错误输出流读取信息
- 通过Runtime实现
- 通过ProcessBuilder实现
- 2.获取进程的返回值
- 3.执行shell中的命令示例
- 案例1:
- 案例2:
- 案例3:
- 案例4:
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下的内嵌命令是不能直接执行的,
- 首先要使用java.lang.Runtime#getRuntime得到一个Runtime实例,然后调用Runtime的exec方法,该方法执行后返回一个Process实例,代表所执行的程序。
- Runtime提供了多个重载的exec方法,其余的方法都是调用如下核心方法实现的:
- cmdarray:包含要调用的命令及其参数的数组。
- envp:环境变量,其中每个元素的环境变量设置格式为name = value,如果子进程应该继承当前进程的环境,则为null。
- dir:子进程的工作目录,如果子进程应该继承当前进程的工作目录,则为null。
API–18–ProcessBuilderprocess类: api 方法 1.destroy()
杀掉子进程。
/**
* 杀死子进程,子进程是否立即终止取决于实现
*/
public abstract void destroy();
/**
* 强制杀死子进程
* @return
*/
public java.lang.Process destroyForcibly() {
destroy();
return this;
}
2.isAlive()
判断子进程是否存活3.exitValue()
返回子进程退出的值
- 只有启动的进程执行完成、或者由于异常退出后,exitValue方法才会有正常的返回值,否则抛出异常。
连接到子进程的输出流
- 可以从该流中读取子进程的标准输出
连接到子进程的输入流
- 写入到该流中的数据作为子进程的标准输入
连接到子进程的错误流
- 获取子进程的错误输出流。如果错误输出被重定向,则不能从该流中读取错误输出。
/**
* 连接到子进程的输出流
* @return
*/
public abstract OutputStream getOutputStream();
/**
* 连接到子进程的输入流
* @return
*/
public abstract InputStream getInputStream();
/**
* 连接到子进程的错误流
* @return
*/
public abstract InputStream getErrorStream();
7.waitFor()
导致当前线程等待
- 导致当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。通过该类提供的方法,可以实现与启动的进程之间通信,达到交互的目的。
- 使当前线程等待,直到子进程退出或者超时
/**
* 使当前线程在必要时等待,直到此Process对象表示的进程已终止
* 如果子进程已经中止,此方法立即返回
* 如果子进程还没有中止,正在调用的线程将被阻塞,直到子进程退出。
* @return
* @throws InterruptedException
*/
public abstract int waitFor() throws InterruptedException;
/**
* 使当前线程等待,直到子进程退出或者超时
* @param timeout
* @param unit
* @return
* @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;
//list the files and directorys under C:\
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) {
//echo the value of NAME
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 the files and directorys under C:\
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();
//echo the value of NAME
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()方法,该方法是非阻塞的,调用立即返回。但是如果进程没有执行完成,则抛出异常。
业务需求:
- 我需要在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("ls /home");
* 如上执行报错:java.io.IOException: Cannot run program "ls /home": error=2, No such file or directory
*
* pb.command("bash", "-c", "ls ", "/home");
* 如上执行,查看的不是/home路径下的文件,而是当前运行目录下的文件
* */
pb.command("bash", "-c", "ls /home");
//merge the error output with the standard output
pb.redirectErrorStream(true);
Process p = pb.start();
//read the standard output
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 {
// Runtime 例子
Process p;
// test.bat中的命令是ipconfig/all
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 {
// ProcessBuilder 例子 Java程序自重启
try {
// 用一条指定的命令去构造一个进程生成器
ProcessBuilder pb = new ProcessBuilder("java", "-jar", "Test3.jar");
// 让这个进程的工作区空间改为F:\dist
// 这样的话,它就会去F:\dist目录下找Test.jar这个文件
pb.directory(new File("F:\dist"));
// 得到进程生成器的环境 变量,这个变量我们可以改,
// 改了以后也会反应到新起的进程里面去
Map<String, String> map = pb.environment();
Process p1 = pb.start();
// 然后就可以对p做自己想做的事情了
// 自己这个时候就可以退出了
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)