08 java.lang.ProcessBuilder
来源:互联网 发布:hql与sql exists in 编辑:程序博客网 时间:2024/06/10 19:14
ProcessBuilder[final]
2015.01.19 By 970655147
这个类主要适用于启动当前操作系统的进程, 有些时候很有用
比如 : 我们想使用一个程序来帮我们使用指定的程序打开指定的文件, 那么我们就可以使用这个
start ->
声明
, 大家可以看看注释
/** * This class is used to create operating system processes. * * <p>Each {@code ProcessBuilder} instance manages a collection * of process attributes. The {@link #start()} method creates a new * {@link Process} instance with those attributes. The {@link * #start()} method can be invoked repeatedly from the same instance * to create new subprocesses with identical or related attributes. * * <p>Each process builder manages these process attributes: * * <ul> * * <li>a <i>command</i>, a list of strings which signifies the * external program file to be invoked and its arguments, if any. * Which string lists represent a valid operating system command is * system-dependent. For example, it is common for each conceptual * argument to be an element in this list, but there are operating * systems where programs are expected to tokenize command line * strings themselves - on such a system a Java implementation might * require commands to contain exactly two elements. * * <li>an <i>environment</i>, which is a system-dependent mapping from * <i>variables</i> to <i>values</i>. The initial value is a copy of * the environment of the current process (see {@link System#getenv()}). * * <li>a <i>working directory</i>. The default value is the current * working directory of the current process, usually the directory * named by the system property {@code user.dir}. * * <li><a name="redirect-input">a source of <i>standard input</i>. * By default, the subprocess reads input from a pipe. Java code * can access this pipe via the output stream returned by * {@link Process#getOutputStream()}. However, standard input may * be redirected to another source using * {@link #redirectInput(Redirect) redirectInput}. * In this case, {@link Process#getOutputStream()} will return a * <i>null output stream</i>, for which: * * <ul> * <li>the {@link OutputStream#write(int) write} methods always * throw {@code IOException} * <li>the {@link OutputStream#close() close} method does nothing * </ul> * * <li><a name="redirect-output">a destination for <i>standard output</i> * and <i>standard error</i>. By default, the subprocess writes standard * output and standard error to pipes. Java code can access these pipes * via the input streams returned by {@link Process#getInputStream()} and * {@link Process#getErrorStream()}. However, standard output and * standard error may be redirected to other destinations using * {@link #redirectOutput(Redirect) redirectOutput} and * {@link #redirectError(Redirect) redirectError}. * In this case, {@link Process#getInputStream()} and/or * {@link Process#getErrorStream()} will return a <i>null input * stream</i>, for which: * * <ul> * <li>the {@link InputStream#read() read} methods always return * {@code -1} * <li>the {@link InputStream#available() available} method always returns * {@code 0} * <li>the {@link InputStream#close() close} method does nothing * </ul> * * <li>a <i>redirectErrorStream</i> property. Initially, this property * is {@code false}, meaning that the standard output and error * output of a subprocess are sent to two separate streams, which can * be accessed using the {@link Process#getInputStream()} and {@link * Process#getErrorStream()} methods. * * <p>If the value is set to {@code true}, then: * * <ul> * <li>standard error is merged with the standard output and always sent * to the same destination (this makes it easier to correlate error * messages with the corresponding output) * <li>the common destination of standard error and standard output can be * redirected using * {@link #redirectOutput(Redirect) redirectOutput} * <li>any redirection set by the * {@link #redirectError(Redirect) redirectError} * method is ignored when creating a subprocess * <li>the stream returned from {@link Process#getErrorStream()} will * always be a <a href="#redirect-output">null input stream</a> * </ul> * * </ul> * * <p>Modifying a process builder's attributes will affect processes * subsequently started by that object's {@link #start()} method, but * will never affect previously started processes or the Java process * itself. * * <p>Most error checking is performed by the {@link #start()} method. * It is possible to modify the state of an object so that {@link * #start()} will fail. For example, setting the command attribute to * an empty list will not throw an exception unless {@link #start()} * is invoked. * * <p><strong>Note that this class is not synchronized.</strong> * If multiple threads access a {@code ProcessBuilder} instance * concurrently, and at least one of the threads modifies one of the * attributes structurally, it <i>must</i> be synchronized externally. * * <p>Starting a new process which uses the default working directory * and environment is easy: * * <pre> {@code * Process p = new ProcessBuilder("myCommand", "myArg").start(); * }</pre> * * <p>Here is an example that starts a process with a modified working * directory and environment, and redirects standard output and error * to be appended to a log file: * * <pre> {@code * 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(new File("myDir")); * File log = new File("log"); * pb.redirectErrorStream(true); * pb.redirectOutput(Redirect.appendTo(log)); * Process p = pb.start(); * assert pb.redirectInput() == Redirect.PIPE; * assert pb.redirectOutput().file() == log; * assert p.getInputStream().read() == -1; * }</pre> * * <p>To start a process with an explicit set of environment * variables, first call {@link java.util.Map#clear() Map.clear()} * before adding environment variables. * * @author Martin Buchholz * @since 1.5 */public final class ProcessBuilder
ProcessBuilder. 属性
// command 为需要运行的程序以及参数 directory为程序所在目录 // environment 为环境变量 // redirectErrorStream=false将子进程的标准输出和错误输出被发送给两个独立的流errorStream // redirects为重定向输入/输出/错误流到指定的文件 private List<String> command; private File directory; private Map<String,String> environment; private boolean redirectErrorStream; private Redirect[] redirects;
ProcessBuilder. command()
// 设置command, 获取command public ProcessBuilder command(List<String> command) { if (command == null) throw new NullPointerException(); this.command = command; return this; } public ProcessBuilder command(String... command) { this.command = new ArrayList<>(command.length); for (String arg : command) this.command.add(arg); return this; } public List<String> command() { return command; }
ProcessBuilder. environment()
// 设置environment, 获取environment public Map<String,String> environment() { SecurityManager security = System.getSecurityManager(); // checkPermission if (security != null) security.checkPermission(new RuntimePermission("getenv.*")); // 获取系统环境变量如果environment是null if (environment == null) environment = ProcessEnvironment.environment(); // assert 确保environment!=null assert environment != null; return environment; }ProcessBuilder environment(String[] envp) // Only for use by Runtime.exec(...envp...)ProcessBuilder environment(String[] envp) { assert environment == null; if (envp != null) { // 获取一个长为envp.length的Map<String, String> environment = ProcessEnvironment.emptyEnvironment(envp.length); assert environment != null; for (String envstring : envp) { // Before 1.5, we blindly passed invalid envstrings // to the child process. // We would like to throw an exception, but do not, // for compatibility with old broken code. // Silently discard any trailing junk. // 空格的index if (envstring.indexOf((int) '\u0000') != -1) envstring = envstring.replaceFirst("\u0000.*", ""); int eqlsign = envstring.indexOf('=', ProcessEnvironment.MIN_NAME_LENGTH); // Silently ignore envstrings lacking the required `='. // 如果每个envString存在”=” 将kvPair放入environment中 if (eqlsign != -1) environment.put(envstring.substring(0,eqlsign), envstring.substring(eqlsign+1)); } } return this; }ProcessEnvironment. emptyEnvironment(int capacity) // Only for use by ProcessBuilder.environment(String[] envp) static Map<String,String> emptyEnvironment(int capacity) { return new ProcessEnvironment(capacity);}final class ProcessEnvironment extends HashMap<String,String>
ProcessBuilder. directory()
// 设置environment, 获取environment public File directory() { return directory; } public ProcessBuilder directory(File directory) { this.directory = directory; return this; }
NullInputStream & NullOutputStream [InnerClass]
// 如果没有配置输入/ 输出/ 错误 的载体, 则使用NullInputStream/ NullOutputStream. INSTANCE 作为载体[详见ProcessImpl] /** * Implements a <a href="#redirect-output">null input stream</a>. */ static class NullInputStream extends InputStream { static final NullInputStream INSTANCE = new NullInputStream(); private NullInputStream() {} public int read() { return -1; } public int available() { return 0; } } static class NullOutputStream extends OutputStream { static final NullOutputStream INSTANCE = new NullOutputStream(); private NullOutputStream() {} public void write(int b) throws IOException { throw new IOException("Stream closed"); } }
Redirect[InnerClass]
// 用于标识重定向在"载体" public static abstract class Redirect { /** * The type of a {@link Redirect}. // 只有PIPE, INHERIT, READ, WRITE, APPEND 五种type */ public enum Type { /** * The type of {@link Redirect#PIPE Redirect.PIPE}. */ PIPE, /** * The type of {@link Redirect#INHERIT Redirect.INHERIT}. */ INHERIT, /** * The type of redirects returned from * {@link Redirect#from Redirect.from(File)}. */ READ, /** * The type of redirects returned from * {@link Redirect#to Redirect.to(File)}. */ WRITE, /** * The type of redirects returned from * {@link Redirect#appendTo Redirect.appendTo(File)}. */ APPEND }; /** * Returns the type of this {@code Redirect}. * @return the type of this {@code Redirect} */ public abstract Type type(); /** * Indicates that subprocess I/O will be connected to the * current Java process over a pipe. * * This is the default handling of subprocess standard I/O. * * <p>It will always be true that * <pre> {@code * Redirect.PIPE.file() == null && * Redirect.PIPE.type() == Redirect.Type.PIPE * }</pre> */ // PIPE INSTANCE public static final Redirect PIPE = new Redirect() { public Type type() { return Type.PIPE; } public String toString() { return type().toString(); }}; /** * Indicates that subprocess I/O source or destination will be the * same as those of the current process. This is the normal * behavior of most operating system command interpreters (shells). * * <p>It will always be true that * <pre> {@code * Redirect.INHERIT.file() == null && * Redirect.INHERIT.type() == Redirect.Type.INHERIT * }</pre> */ // PIPE INSTANCE public static final Redirect INHERIT = new Redirect() { public Type type() { return Type.INHERIT; } public String toString() { return type().toString(); }}; /** * Returns the {@link File} source or destination associated * with this redirect, or {@code null} if there is no such file. * * @return the file associated with this redirect, * or {@code null} if there is no such file */ public File file() { return null; } /** * When redirected to a destination file, indicates if the output * is to be written to the end of the file. */ boolean append() { throw new UnsupportedOperationException(); } /** * Returns a redirect to read from the specified file. * * <p>It will always be true that * <pre> {@code * Redirect.from(file).file() == file && * Redirect.from(file).type() == Redirect.Type.READ * }</pre> * * @throws NullPointerException if the specified file is null * @return a redirect to read from the specified file */ // READ INSTANCE public static Redirect from(final File file) { if (file == null) throw new NullPointerException(); return new Redirect() { public Type type() { return Type.READ; } public File file() { return file; } public String toString() { return "redirect to read from file \"" + file + "\""; } }; } /** * Returns a redirect to write to the specified file. * If the specified file exists when the subprocess is started, * its previous contents will be discarded. * * <p>It will always be true that * <pre> {@code * Redirect.to(file).file() == file && * Redirect.to(file).type() == Redirect.Type.WRITE * }</pre> * * @throws NullPointerException if the specified file is null * @return a redirect to write to the specified file */ // WRITE INSTANCE public static Redirect to(final File file) { if (file == null) throw new NullPointerException(); return new Redirect() { public Type type() { return Type.WRITE; } public File file() { return file; } public String toString() { return "redirect to write to file \"" + file + "\""; } boolean append() { return false; } }; } /** * Returns a redirect to append to the specified file. * Each write operation first advances the position to the * end of the file and then writes the requested data. * Whether the advancement of the position and the writing * of the data are done in a single atomic operation is * system-dependent and therefore unspecified. * * <p>It will always be true that * <pre> {@code * Redirect.appendTo(file).file() == file && * Redirect.appendTo(file).type() == Redirect.Type.APPEND * }</pre> * * @throws NullPointerException if the specified file is null * @return a redirect to append to the specified file */ // APPEND INSTANCE public static Redirect appendTo(final File file) { if (file == null) throw new NullPointerException(); return new Redirect() { public Type type() { return Type.APPEND; } public File file() { return file; } public String toString() { return "redirect to append to file \"" + file + "\""; } boolean append() { return true; } }; } /** * Compares the specified object with this {@code Redirect} for * equality. Returns {@code true} if and only if the two * objects are identical or both objects are {@code Redirect} * instances of the same type associated with non-null equal * {@code File} instances. */ public boolean equals(Object obj) { // 如果引用相等 直接返回true if (obj == this) return true; // RTTI if (! (obj instanceof Redirect)) return false; // 先比较type 在比较file Redirect r = (Redirect) obj; if (r.type() != this.type()) return false; assert this.file() != null; return this.file().equals(r.file()); } /** * Returns a hash code value for this {@code Redirect}. * @return a hash code value for this {@code Redirect} */ public int hashCode() { File file = file(); if (file == null) return super.hashCode(); else return file.hashCode(); } /** * No public constructors. Clients must use predefined * static {@code Redirect} instances or factory methods. */ //构造方法私有化 // 保证了除了本身提供的Redirect对象 和from, to方法构造Redirect外 不能另外构建对象 private Redirect() {} }
ProcessBuilder. redirect Input/ Output/ Error(Redirect source)
public ProcessBuilder redirectInput(Redirect source) { // 如果source的type是write或者append 抛出异常 // source的type 属于 read, pipe, inherit if (source.type() == Redirect.Type.WRITE || source.type() == Redirect.Type.APPEND) throw new IllegalArgumentException( "Redirect invalid for reading: " + source); // 重定向输入 redirects()[0] = source; return this; } public ProcessBuilder redirectOutput(Redirect destination) { if (destination.type() == Redirect.Type.READ) throw new IllegalArgumentException( "Redirect invalid for writing: " + destination); redirects()[1] = destination; return this; } public ProcessBuilder redirectError(Redirect destination) { if (destination.type() == Redirect.Type.READ) throw new IllegalArgumentException( "Redirect invalid for writing: " + destination); redirects()[2] = destination; return this; } public ProcessBuilder redirectInput(File file) { return redirectInput(Redirect.from(file)); } public ProcessBuilder redirectOutput(File file) { return redirectOutput(Redirect.to(file)); } public ProcessBuilder redirectError(File file) { return redirectError(Redirect.to(file)); } private Redirect[] redirects() { // 如果redirects没有初始化 则新建一个三个对象的Redirect数组 // 表示输入/输出/错误重定向 if (redirects == null) redirects = new Redirect[] { Redirect.PIPE, Redirect.PIPE, Redirect.PIPE }; return redirects; } // 默认的输入/ 输出/ 错误 重定向为PIPE public Redirect redirectInput() { return (redirects == null) ? Redirect.PIPE : redirects[0]; } public Redirect redirectOutput() { return (redirects == null) ? Redirect.PIPE : redirects[1]; } public Redirect redirectError() { return (redirects == null) ? Redirect.PIPE : redirects[2]; }
ProcessBuilder. redirectErrorStream()
public boolean redirectErrorStream() { return redirectErrorStream; } public ProcessBuilder redirectErrorStream(boolean redirectErrorStream) { this.redirectErrorStream = redirectErrorStream; return this; }
ProcessBuilder. inheritIO()
public ProcessBuilder inheritIO() { // 将redirects都设置为Redirect.INHERIT Arrays.fill(redirects(), Redirect.INHERIT); return this; }
ProcessBuilder. start()
// 这个是ProcessBuilder的核心业务方法, 也是我们使用到的最多的方法, 启动一个进程 public Process start() throws IOException { // Must convert to array first -- a malicious user-supplied // list might try to circumvent the security check. String[] cmdarray = command.toArray(new String[command.size()]); // toArray不是会新建一个数组吗 为什么还需要clone..? cmdarray = cmdarray.clone(); // 校验是否存在null参数 for (String arg : cmdarray) if (arg == null) throw new NullPointerException(); // Throws IndexOutOfBoundsException if command is empty // 第一个字符串为要启动的程序 String prog = cmdarray[0]; // security check SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkExec(prog); } // 为什么要新建一个字符串?并发? String dir = directory == null ? null : directory.toString(); try { // 新建一个进程实例 return ProcessImpl.start(cmdarray, environment, dir, redirects, redirectErrorStream); } catch (IOException | IllegalArgumentException e) { String exceptionInfo = ": " + e.getMessage(); Throwable cause = e; if ((e instanceof IOException) && security != null) { // Can not disclose the fail reason for read-protected files. // 不能公开读取受保护的文件 exceptionInfo=”” try { security.checkRead(prog); } catch (AccessControlException ace) { exceptionInfo = ""; cause = ace; } } // It's much easier for us to create a high-quality error // message than the low-level C code which found the problem. // 抛出异常 throw new IOException( "Cannot run program \"" + prog + "\"" + (dir == null ? "" : " (in directory \"" + dir + "\")") + exceptionInfo, cause); } } // System-dependent portion of ProcessBuilder.start() static Process start(String cmdarray[], java.util.Map<String,String> environment, String dir, ProcessBuilder.Redirect[] redirects, boolean redirectErrorStream) throws IOException{ // ... String envblock = ProcessEnvironment.toEnvironmentBlock(environment); FileInputStream f0 = null; FileOutputStream f1 = null; FileOutputStream f2 = null; try { long[] stdHandles; if (redirects == null) { stdHandles = new long[] { -1L, -1L, -1L }; } else { stdHandles = new long[3]; // 如果输入type为pipe 设置输入标志位为-1L // 如果是inherit 设置输入标志位为fdAccess.getHandle(FileDescriptor.in) // 否则 f0设置为对应输入流重定向文件的FileInputStream,设置输入标志位为f0.getFD() if (redirects[0] == Redirect.PIPE) stdHandles[0] = -1L; else if (redirects[0] == Redirect.INHERIT) stdHandles[0] = fdAccess.getHandle(FileDescriptor.in); else { f0 = new FileInputStream(redirects[0].file()); stdHandles[0] = fdAccess.getHandle(f0.getFD()); } if (redirects[1] == Redirect.PIPE) stdHandles[1] = -1L; else if (redirects[1] == Redirect.INHERIT) stdHandles[1] = fdAccess.getHandle(FileDescriptor.out); else { f1 = newFileOutputStream(redirects[1].file(), redirects[1].append()); stdHandles[1] = fdAccess.getHandle(f1.getFD()); } if (redirects[2] == Redirect.PIPE) stdHandles[2] = -1L; else if (redirects[2] == Redirect.INHERIT) stdHandles[2] = fdAccess.getHandle(FileDescriptor.err); else { f2 = newFileOutputStream(redirects[2].file(), redirects[2].append()); stdHandles[2] = fdAccess.getHandle(f2.getFD()); } } // 新建一个进程实例 return new ProcessImpl(cmdarray, envblock, dir, stdHandles, redirectErrorStream); } finally { // In theory, close() can throw IOException // (although it is rather unlikely to happen here) // 理论上来讲close()操作可能会抛出IOException // 但是在这里可能不太可能会出现 try { if (f0 != null) f0.close(); } finally { try { if (f1 != null) f1.close(); } finally { if (f2 != null) f2.close(); } } } }
->
ok, ProcessBuilder 到此结束了, 这个类需要最核心的就是start方法了, 以及对于重定向的理解
资源下载 : http://download.csdn.net/detail/u011039332/9061385
注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!
0 0
- 08 java.lang.ProcessBuilder
- java.lang.ProcessBuilder
- java.lang.ProcessBuilder用法
- 学习java.lang.ProcessBuilder类
- java.lang.ProcessBuilder类 小结
- java.lang.ProcessBuilder类小结
- java.lang.ProcessBuilder类总结
- 深入研究java.lang.ProcessBuilder类
- 深入研究java.lang.ProcessBuilder类
- 深入研究java.lang.ProcessBuilder类 收藏
- 深入研究java.lang.ProcessBuilder类
- 深入理解java.lang.ProcessBuilder类
- 深入研究java.lang.ProcessBuilder类
- 深入研究java.lang.ProcessBuilder类
- 深入研究java.lang.ProcessBuilder类
- java.lang.ProcessBuilder类(系统进程)
- 黑马程序员——java.lang.Process和java.lang.ProcessBuilder
- 本地mapReduce项目报错:java.lang.NullPointerException at java.lang.ProcessBuilder.start...
- SVM、BP了解以及性能比较
- 比较C++中的4种类型转换方式
- Matlab 文件夹遍历并更改图片尺寸
- 差距固然存在,但并不令人遗憾,正是差距和为弥补差距所付出的努力,加强了生命的张力,使其更有层次更加多元。
- 44_02 nginx
- 08 java.lang.ProcessBuilder
- led驱动程序设计
- UGUI简述
- Hession
- [转载]mysql远程连接错误1130的解决方法
- NOIP2011 选择客栈 题解(最简方法,超短代码)
- hdu 2665 区间第K大 主席树入门
- 数据结构 字符串模式匹配之BF算法
- http://www.gisinternals.com/aboutgisinternals.html