浅析Java.lang.ProcessBuilder类

       最近由于工作需要把用户配置的Hive命令在Linux环境下执行,专门做了一个用户管理界面特地研究了这个不经常用得ProcessBuilder类。所以把自己的学习的资料总结一下。

        

一、概述
      ProcessBuilder类是J2SE 1.5在java.lang中新添加的一个新类,此类用于创建操作系统进程,它提供一种启动和管理进程(也就是应用程序)的方法。在J2SE 1.5之前,都是由Process类处来实现进程的控制管理。
      每个 ProcessBuilder 实例管理一个进程属性集。它的start() 方法利用这些属性创建一个新的 Process 实例。start() 方法可以从同一实例重复调用,以利用相同的或相关的属性创建新的子进程。 (我在《深入研究java.lang.Runtime类》中讲过,进程也可以由Runtime.exec()启动。)

每个进程生成器(即ProcessBuilder对象)管理这些进程属性:

     命令 是一个字符串列表,它表示要调用的外部程序文件及其参数(如果有)。在此,表示有效的操作系统命令的字符串列表是依赖于系统的。例如,每一个总体变量,通常都要成为此列表中的元素,但有一些操作系统,希望程序能自己标记命令行字符串——在这种系  统中,Java 实现可能需要命令确切地包含这两个元素。 
    环境 是从变量 到值 的依赖于系统的映射。初始值是当前进程环境的一个副本(请参阅 System.getenv())。 
    工作目录 默认值是当前进程的当前工作目录,通常根据系统属性 user.dir 来命名。 
    redirectErrorStream 属性。最初,此属性为 false,意思是子进程的标准输出和错误输出被发送给两个独立的流,这些流可以通过 Process.getInputStream() 和 Process.getErrorStream() 方法来访问。如果将值设置为 true,标准错误将与标准输出合并。这使得关联错误消息和相应的输出变得更容易。在此情况下,合并的数据可从 Process.getInputStream() 返回的流读取,而从 Process.getErrorStream() 返回的流读取将直接到达文件尾。

    既然有Process类,那为什么还要发明个ProcessBuilder类呢?ProcessBuilder和Process两个类有什么区别呢? 

      ProcessBuilder为进程提供了更多的控制,例如,可以设置当前工作目录,还可以改变环境参数。而Process的功能相对来说简单的多。ProcessBuilder是一个final类,有两个带参数的构造方法,你可以通过构造方法来直接创建ProcessBuilder的对象。而Process是一个抽象类,一般都通过Runtime.exec()和ProcessBuilder.start()来间接创建其实例。

 

 
 
注意:
      修改进程构建器的属性将影响后续由该对象的 start() 方法启动的进程,但从不会影响以前启动的进程或 Java 自身的进程。
      ProcessBuilder类不是同步的。如果多个线程同时访问一个 ProcessBuilder,而其中至少一个线程从结构上修改了其中一个属性,它必须保持外部同步。
 
启动一个使用默认工作目录和环境的新进程: 
Process p = new ProcessBuilder("myCommand", "myArg").start();  
下面是一个利用修改过的工作目录和环境启动进程的例子:  
 ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
 Map env = pb.environment();
 env.put("VAR1", "myValue");
 env.remove("OTHERVAR");
 env.put("VAR2", env.get("VAR1") + "suffix");
 pb.directory("myDir");
 Process p = pb.start();
 要利用一组明确的环境变量启动进程,在添加环境变量之前,首先调用 Map.clear()。 
二、API预览
     构造方法摘要 
    ProcessBuilder(List command) 
      利用指定的操作系统程序和参数构造一个进程生成器。 
    ProcessBuilder(String... command) 
      利用指定的操作系统程序和参数构造一个进程生成器。
 
     方法摘要 
    command() 
      返回此进程生成器的操作系统程序和参数。 
    command(List command) 
      设置此进程生成器的操作系统程序和参数。 
    command(String... command) 
      设置此进程生成器的操作系统程序和参数。 
    directory() 
      返回此进程生成器的工作目录。 
    directory(File directory) 
      设置此进程生成器的工作目录。 
    environment() 
      返回此进程生成器环境的字符串映射视图。 
    redirectErrorStream() 
      通知进程生成器是否合并标准错误和标准输出。 
    redirectErrorStream(boolean redirectErrorStream) 
      设置此进程生成器的 redirectErrorStream 属性。 
     start() 
    使用此进程生成器的属性启动一个新进程实例Process ,可以操作 Process对象:详解 
三、常见应用
      若要使用ProcessBuilder创建一个进程,只需要创建ProcessBuilder的一个实例,指定该进程的名称和所需参数。要执行此程序,调用该实例上的start()即可。
1,下面上一个执行Windows记事本的例子。注意它将要编辑的文件名指定为一个参数。
class PBDemo { 
        public static void main(String args[]) { 
                try { 
                        ProcessBuilder proc = new ProcessBuilder("notepad.exe", "testfile"); 
                        proc.start(); 
                } catch (Exception e) { 
                        System.out.println("Error executing notepad."); 
                } 
        } 
}
2, ProcessBuilder的应用简单来说就是,先生成一个ProcessBuilder对象:

ProcessBuilder提供了两个构造函数,ProcessBuilder(List command) 和 ProcessBuilder(String... command

我这里使用的是第二个,因为是需要在Linux系统上执行shell脚本,所以,我的构造函数为:

ProcessBuilder pb = new ProcessBuilder("sh"); (ps:你也可以对应的使用“Python”或者在windows上使用“cmd”)

执行的命令的应用程序已经选好了,那我们的输入和输出呢,怎么设置,这是我们关心的地方。

推荐使用redirectInput(File file) ,让我们用这个方法来获取输入,同理使用redirectOutput(File file)

来处理输出,如果有错误的话,还需要使用redirectError(File file)

由于涉及到的参数都是File类型的,所以,你需要先生成这几个文件,然后再使用它们

执行完后,可以去outfile里面查看执行结果,你也可以把结果读出后返回,将file.sh和outfile这两个临时文件删除。

 

package com.pmqin.quartz.domian;


import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;


public class ProcessBuildertest {

    public static void main(String[] args) {
        String file = "!/bin/sh\r\n" // linux 的换行是\n,注意换
                    + "a=\'Hello world\'\r\n" + "echo $a\r\n";
            String result = Process("sh", file,true);
    System.out.println(result);

        } catch (Exception e) {
            System.out.println("Error executing notepad.");
        }

    }


public static String Process(String cmd, String commandlist,boolean isSavefile) throws IOException, InterruptedException {
        
        File input = new File("./file.sh");
        createNewFile(input);

        PrintWriter print = new PrintWriter(input);
        print.append(commandlist);
        print.flush();
        print.close();
        
        String result = "SUCCESS";
        try {
            File output = null;
            if (isSavefile) {
                output = new File("./outfile");
                createNewFile(output);
            }
            

            ProcessBuilder pb = new ProcessBuilder(cmd);
            pb.redirectErrorStream(true);//如果将值设置为 true,标准错误将与标准输出合并,在此情况下,合并的数据可从 Process.getInputStream() 返回的流读取
            pb.redirectInput(input);
            if (isSavefile) {
                pb.redirectOutput(output); //表示把输出重定向到指定的文件里面
            }            

            Process process = pb.start();//异步的
        
            // 获取执行的结果
            if (!isSavefile) {
                InputStream in = process.getInputStream();//同步
                System.out.println("等待执行完成");
                String  streamtxt=getInputStream(in);                
                System.out.println(streamtxt);
            }
            if (process.waitFor() != 0) {
                //InputStream error = process.getErrorStream();
                result="Err";
            }
            process.destroy();

        } catch (IOException e) {
            result = "FAIL";
            e.printStackTrace();
        }

        return result;
    }


/**
     * inputStream 文件流 转成字符串
     * @param inputStream 文件流
     * @return
     * @throws IOException
     */
    public static String getInputStream(InputStream inputStream) throws IOException {

        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "gb2312"));
        String line = null;

        while ((line = bufferedReader.readLine()) != null) {

            stringBuilder.append(System.getProperty("line.separator"));

            stringBuilder.append(line);
        }
        return stringBuilder.toString();

    }
    
    /**
     * 判断文件是否存在,不存在就创建
     * @param file
     * @throws IOException 
     */
    public static void createNewFile(File file) throws IOException {        
        if (!file.exists()) {
                file.createNewFile();
        }
    }

 

你可能感兴趣的:(浅析Java.lang.ProcessBuilder类)