API--17--Process

Posted 高高for 循环

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了API--17--Process相关的知识,希望对你有一定的参考价值。

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

文章目录


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();
		


以上是关于API--17--Process的主要内容,如果未能解决你的问题,请参考以下文章

什么是索引,非聚集索引可以是非唯一的吗?

剑英陪你玩转图形学打通任督二脉

如何写好B端产品的技术方案?

自我介绍博客

数字货币镰刀之路,ZG交易所割韭菜,比特币回调?

RabbitMQ基础——和——持久化机制