API--17--Process

API--17--Process,第1张

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录
  • 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下的内嵌命令是不能直接执行的,
1. 采用Runtime的exec执行程序时
  • 首先要使用java.lang.Runtime#getRuntime得到一个Runtime实例,然后调用Runtime的exec方法,该方法执行后返回一个Process实例,代表所执行的程序。
  • Runtime提供了多个重载的exec方法,其余的方法都是调用如下核心方法实现的:
  • cmdarray:包含要调用的命令及其参数的数组
  • envp:环境变量,其中每个元素的环境变量设置格式为name = value,如果子进程应该继承当前进程的环境,则为null。
  • dir:子进程的工作目录,如果子进程应该继承当前进程的工作目录,则为null。
2. 采用ProcessBuilder类启动一个新的程序

API–18–ProcessBuilder
process类: api 方法

1.destroy()
杀掉子进程。
 /**
     * 杀死子进程,子进程是否立即终止取决于实现
     */
    public abstract void destroy();

    /**
     * 强制杀死子进程
     * @return
     */
    public java.lang.Process destroyForcibly() {
        destroy();
        return this;
    }


2.isAlive()
判断子进程是否存活

3.exitValue()
返回子进程退出的值
  • 只有启动的进程执行完成、或者由于异常退出后,exitValue方法才会有正常的返回值,否则抛出异常。
4.getOutputStream(),
连接到子进程的输出流
  • 可以从该流中读取子进程的标准输出
5.getInputStream()
连接到子进程的输入流
  • 写入到该流中的数据作为子进程的标准输入
6.getErrorStream ()
连接到子进程的错误流
  • 获取子进程的错误输出流。如果错误输出被重定向,则不能从该流中读取错误输出。
   /**
     * 连接到子进程的输出流
     * @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()方法,该方法是非阻塞的,调用立即返回。但是如果进程没有执行完成,则抛出异常。
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("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();
		}
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/797956.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-06
下一篇 2022-05-06

发表评论

登录后才能评论

评论列表(0条)

保存