最近由于工作需要把用户配置的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<String, String> 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<String> command) 
      利用指定的操作系统程序和参数构造一个进程生成器。 
    ProcessBuilder(String... command) 
      利用指定的操作系统程序和参数构造一个进程生成器。

 
    方法摘要 
    command() 
      返回此进程生成器的操作系统程序和参数。 
    command(List<String> 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<String> 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类的更多相关文章

  1. 浅析Java.lang.Process类

    一.概述      Process类是一个抽象类(所有的方法均是抽象的),封装了一个进程(即一个执行程序).      Process 类提供了执行从进程输入.执行输出到进程.等待进程完成.检查进程的 ...

  2. 深入研究java.lang.ProcessBuilder类

     深入研究java.lang.ProcessBuilder类 一.概述       ProcessBuilder类是J2SE 1.5在java.lang中新添加的一个新类,此类用于创建操作系统进程,它 ...

  3. 浅析Java.lang.Runtime类

    一.概述      Runtime类封装了运行时的环境.每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接.      一般不能实例化一个Runtime对象, ...

  4. 深入研究java.lang.Process类

    一.概述 Process类是一个抽象类(所有的方法均是抽象的),封装了一个进程(即一个执行程序).       Process 类提供了执行从进程输入.执行输出到进程.等待进程完成.检查进程的退出状态 ...

  5. java.lang.String 类的所有方法

    java.lang.String 类的所有方法 方法摘要 char charAt(int index) 返回指定索引处的 char 值. int codePointAt(int index) 返回指定 ...

  6. java.lang.NullPointerException at java.lang.ProcessBuilder.start(Unknown Source) at org.apache.hadoop.util.Shell.runCommand(Shell.java:482)

    1:问题出现的原因,部署好的hadoop-2.6.4进行window10操作hadoop api出现的错误,具体错误是我向hdfs上传文件,还好点,之前解决过,这里不叙述,这里说一下从hdfs下载文件 ...

  7. Java 线程--继承java.lang.Thread类实现线程

    现实生活中的很多事情是同时进行的,Java中为了模拟这种状态,引入了线程机制.先来看线程的基本概念. 线程是指进程中的一个执行场景,也就是执行流程,进程和线程的区别: 1.每个进程是一个应用程序,都有 ...

  8. Java反射——java.lang.Class 类简介

    Java的基本思想之一是万事万物即对象,类也是一种对象.但是类是什么对象呢?Java中的类是java.lang.Class的实例化对象,这被成为类类型. //java.lang.Class类中的的主要 ...

  9. 深入研究java.lang.ThreadLocal类 (转)

    深入研究java.lang.ThreadLocal类     一.概述   ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是thr ...

随机推荐

  1. UE4实现风格化渲染(一):UserNormalTranslator工具的使用

    最近会在UE4上实现风格化渲染的需求,所以也借机写一下相关的制作教程.对应日系风格化渲染技法来说,关键还是法线的处理.   法线处理以前翻译的资料很多了,所以也不多做解释了,比如下图是最新的UE4上的 ...

  2. mysql优化limit分页

  3. Java工具Eclipse

    一.下载Eclipse 从官网渠道下载或从公司共享软件目录下载均可.    a) http://www.eclipse.org/downloads/eclipse-packages/          ...

  4. 在SQL语句中加入时间比较作为查询条件

    select * from 表名 where 列名 = ? and DATEDIFF(hh,时间列,'2016-08-22 15:05:59.000')<9

  5. cocostudio做出来的界面如何进行分辨率适配,兼论cocos2dx3的多分辨率适配机制,以及retina适配机制

    cocos有很多代码实际上都不再使用了,看代码时反而误导了程序员. 比如一个简单的分辨率适配,我查到了setContentSize,然后调用setContentSize,毫无用处啊!于是乎,我到处查资 ...

  6. linux建立文件夹软连接

    linux建立文件夹软连接,并强制覆盖 ln -sfn /home/var/log/httpd/logs logs 这将在当前目录下建立logs软连接,指向/home/var/log/httpd/lo ...

  7. 【Git学习笔记】远程仓库

    第一种情景:本地初始化一个Git仓库后,接着又在github上创建了一个Git仓库,现在要让这两个仓库进行远程同步. 1. 关联本地仓库就和远程仓库  $ git remote add origin ...

  8. 简单的jquery tab

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. java中字节流与字符流的区别

    字节流 在I/O类库中,java.io.InputStream和java.io.OutputStream分别表示字节输入流和字节输出流,它们都是抽象类,不能实例化,数据流中的最小单位是字节,所以叫做字 ...

  10. 软件测试基础homework3

    //本次的作业为/******************************************************* * Finds and prints n prime integers ...