最近由于工作需要把用户配置的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. CSS方法论完全总结

    软件开发领域所有的工程问题,归根结底衍生自一个问题:代码量大了怎么办? 对于CSS而言,因代码量增大导致的核心问题是命名冲突. 解决命名冲突的方法论是模块化,围绕此方法论,演化出种种模块化方案. 一. ...

  2. yxcms后台验证码不显示?怎么取消yxcms后台验证码

    嗨,大家好,我是YXCMS的小M老湿,(其实还是习惯大家叫我猪猪吧!)今天又要分享一则yxcms的使用技巧,当然也是yxcms用户在使用过程中很容易出现的小白问题,当然还是同样,yxcms的大神级别的 ...

  3. python计算apache总内存

    #!/usr/bin/env python import os from subprocess import Popen, PIPE def getPid(): p=Popen(['pidof','h ...

  4. solr了解的一些东西

    近一周学习了一下solr,大概了解了一些东西,学会了如何为数据库中数据添加索引,中文分词怎样使用的一些知识 1.在网上的大多资料都是使用solr要安装tomacat,一时很迷茫,tomacat我理解是 ...

  5. vert.x学习(四),使用模板解析器ClassLoaderTemplateResolver

    在vert.x中使用模板解析,可以为我们带来很多方便.我这里学习了一下ClassLoaderTemplateResolver的简单使用.这次工程配置与上篇一样,不需要做任何多的配置.直接编写代码就可以 ...

  6. linq group by多个字段,返回多个字段.

    直接上例子.var wflist = from u in db.TWelFare where u.fy_no == fy_no orderby u.we_no group u by new { wen ...

  7. 解决Entity Framework中DateTime类型字段异常

    从 datetime2 数据类型到 datetime 数据类型的转换产生一个超出范围的值 具体的错误原因是:C#中的DateTime类型比SqlServer中的datetime范围大.SqlServe ...

  8. 上下箭头选中 选项事件 JS

    //上下键 选择事件 searchBackgroud 为样式,只做标记,无实质样式,因为和其他样式不兼容,只能添加CSS $(document).keydown(function (event) { ...

  9. ios通知机制

  10. swift language

    API reference Swift UIKit Swift 菜鸟教程 Great Installed Visual Studio Code, I found I cannot open it fr ...