Java/Development Class/ProcessBuilder
Содержание
Exec Helper
<source lang="java">
/*
* Convenience methods for executing non-Java processes. * Copyright (C) 2005 Stephen Ostermiller * http://ostermiller.org/contact.pl?regarding=Java+Utilities * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * See COPYING.TXT for details. */
import java.io.*; /**
* Convenience methods for executing non-Java processes. * More information about this class is available from . * * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities * @since ostermillerutils 1.06.00 */
public final class ExecHelper {
/** * Executes the specified command and arguments in a separate process, and waits for the * process to finish.*
* Output from the process is expected to be text in the system"s default character set. * <p> * No input is passed to the process on STDIN. * * @param cmdarray array containing the command to call and its arguments. * @return The results of the execution in an ExecHelper object. * @throws SecurityException if a security manager exists and its checkExec method doesn"t allow creation of a subprocess. * @throws IOException - if an I/O error occurs * @throws NullPointerException - if cmdarray is null * @throws IndexOutOfBoundsException - if cmdarray is an empty array (has length 0). * * @since ostermillerutils 1.06.00 */ public static ExecHelper exec(String[] cmdarray) throws IOException { return new ExecHelper(Runtime.getRuntime().exec(cmdarray), null); } /** * Executes the specified command and arguments in a separate process, and waits for the * process to finish. * <p> * Output from the process is expected to be text in the system"s default character set. * <p> * No input is passed to the process on STDIN. * * @param cmdarray array containing the command to call and its arguments. * @param envp array of strings, each element of which has environment variable settings in format name=value. * @return The results of the execution in an ExecHelper object. * @throws SecurityException if a security manager exists and its checkExec method doesn"t allow creation of a subprocess. * @throws IOException - if an I/O error occurs * @throws NullPointerException - if cmdarray is null * @throws IndexOutOfBoundsException - if cmdarray is an empty array (has length 0). * * @since ostermillerutils 1.06.00 */ public static ExecHelper exec(String[] cmdarray, String[] envp) throws IOException { return new ExecHelper(Runtime.getRuntime().exec(cmdarray, envp), null); } /** * Executes the specified command and arguments in a separate process, and waits for the * process to finish. * <p> * Output from the process is expected to be text in the system"s default character set. * <p> * No input is passed to the process on STDIN. * * @param cmdarray array containing the command to call and its arguments. * @param envp array of strings, each element of which has environment variable settings in format name=value. * @param dir the working directory of the subprocess, or null if the subprocess should inherit the working directory of the current process. * @return The results of the execution in an ExecHelper object. * @throws SecurityException if a security manager exists and its checkExec method doesn"t allow creation of a subprocess. * @throws IOException - if an I/O error occurs * @throws NullPointerException - if cmdarray is null * @throws IndexOutOfBoundsException - if cmdarray is an empty array (has length 0). * * @since ostermillerutils 1.06.00 */ public static ExecHelper exec(String[] cmdarray, String[] envp, File dir) throws IOException { return new ExecHelper(Runtime.getRuntime().exec(cmdarray, envp, dir), null); } /** * Executes the specified command and arguments in a separate process, and waits for the * process to finish. * <p> * No input is passed to the process on STDIN. * * @param cmdarray array containing the command to call and its arguments. * @param charset Output from the executed command is expected to be in this character set. * @return The results of the execution in an ExecHelper object. * @throws SecurityException if a security manager exists and its checkExec method doesn"t allow creation of a subprocess. * @throws IOException - if an I/O error occurs * @throws NullPointerException - if cmdarray is null * @throws IndexOutOfBoundsException - if cmdarray is an empty array (has length 0). * * @since ostermillerutils 1.06.00 */ public static ExecHelper exec(String[] cmdarray, String charset) throws IOException { return new ExecHelper(Runtime.getRuntime().exec(cmdarray), charset); } /** * Executes the specified command and arguments in a separate process, and waits for the * process to finish. * <p> * No input is passed to the process on STDIN. * * @param cmdarray array containing the command to call and its arguments. * @param envp array of strings, each element of which has environment variable settings in format name=value. * @param charset Output from the executed command is expected to be in this character set. * @return The results of the execution in an ExecHelper object. * @throws SecurityException if a security manager exists and its checkExec method doesn"t allow creation of a subprocess. * @throws IOException - if an I/O error occurs * @throws NullPointerException - if cmdarray is null * @throws IndexOutOfBoundsException - if cmdarray is an empty array (has length 0). * * @since ostermillerutils 1.06.00 */ public static ExecHelper exec(String[] cmdarray, String[] envp, String charset) throws IOException { return new ExecHelper(Runtime.getRuntime().exec(cmdarray, envp), charset); } /** * Executes the specified command and arguments in a separate process, and waits for the * process to finish. * <p> * No input is passed to the process on STDIN. * * @param cmdarray array containing the command to call and its arguments. * @param envp array of strings, each element of which has environment variable settings in format name=value. * @param dir the working directory of the subprocess, or null if the subprocess should inherit the working directory of the current process. * @param charset Output from the executed command is expected to be in this character set. * @return The results of the execution in an ExecHelper object. * @throws SecurityException if a security manager exists and its checkExec method doesn"t allow creation of a subprocess. * @throws IOException - if an I/O error occurs * @throws NullPointerException - if cmdarray is null * @throws IndexOutOfBoundsException - if cmdarray is an empty array (has length 0). * * @since ostermillerutils 1.06.00 */ public static ExecHelper exec(String[] cmdarray, String[] envp, File dir, String charset) throws IOException { return new ExecHelper(Runtime.getRuntime().exec(cmdarray, envp, dir), charset); } /** * Executes the specified command using a shell. On windows uses cmd.exe or command.exe. * On other platforms it uses /bin/sh. * <p> * A shell should be used to execute commands when features such as file redirection, pipes, * argument parsing are desired. * <p> * Output from the process is expected to be text in the system"s default character set. * <p> * No input is passed to the process on STDIN. * * @param command String containing a command to be parsed by the shell and executed. * @return The results of the execution in an ExecHelper object. * @throws SecurityException if a security manager exists and its checkExec method doesn"t allow creation of a subprocess. * @throws IOException - if an I/O error occurs * @throws NullPointerException - if command is null * * @since ostermillerutils 1.06.00 */ public static ExecHelper execUsingShell(String command) throws IOException { return execUsingShell(command, null); } /** * Executes the specified command using a shell. On windows uses cmd.exe or command.exe. * On other platforms it uses /bin/sh. * <p> * A shell should be used to execute commands when features such as file redirection, pipes, * argument parsing are desired. * <p> * No input is passed to the process on STDIN. * * @param command String containing a command to be parsed by the shell and executed. * @param charset Output from the executed command is expected to be in this character set. * @return The results of the execution in an ExecHelper object. * @throws SecurityException if a security manager exists and its checkExec method doesn"t allow creation of a subprocess. * @throws IOException - if an I/O error occurs * @throws NullPointerException - if command is null * * @since ostermillerutils 1.06.00 */ public static ExecHelper execUsingShell(String command, String charset) throws IOException { if (command == null) throw new NullPointerException(); String[] cmdarray; String os = System.getProperty("os.name"); if (os.equals("Windows 95") || os.equals("Windows 98") || os.equals("Windows ME")){ cmdarray = new String[]{"command.exe", "/C", command}; } else if (os.startsWith("Windows")){ cmdarray = new String[]{"cmd.exe", "/C", command}; } else { cmdarray = new String[]{"/bin/sh", "-c", command}; } return new ExecHelper(Runtime.getRuntime().exec(cmdarray), charset); } /** * Take a process, record its standard error and standard out streams, wait for it to finish * * @param process process to watch * @throws SecurityException if a security manager exists and its checkExec method doesn"t allow creation of a subprocess. * @throws IOException - if an I/O error occurs * @throws NullPointerException - if cmdarray is null * @throws IndexOutOfBoundsException - if cmdarray is an empty array (has length 0). * * @since ostermillerutils 1.06.00 */ private ExecHelper(Process process, String charset) throws IOException { StringBuffer output = new StringBuffer(); StringBuffer error = new StringBuffer(); Reader stdout; Reader stderr; if (charset == null){ // This is one time that the system charset is appropriate, // don"t specify a character set. stdout = new InputStreamReader(process.getInputStream()); stderr = new InputStreamReader(process.getErrorStream()); } else { stdout = new InputStreamReader(process.getInputStream(), charset); stderr = new InputStreamReader(process.getErrorStream(), charset); } char[] buffer = new char[1024]; boolean done = false; boolean stdoutclosed = false; boolean stderrclosed = false; while (!done){ boolean readSomething = false; // read from the process"s standard output if (!stdoutclosed && stdout.ready()){ readSomething = true; int read = stdout.read(buffer, 0, buffer.length); if (read < 0){ readSomething = true; stdoutclosed = true; } else if (read > 0){ readSomething = true; output.append(buffer, 0, read); } } // read from the process"s standard error if (!stderrclosed && stderr.ready()){ int read = stderr.read(buffer, 0, buffer.length); if (read < 0){ readSomething = true; stderrclosed = true; } else if (read > 0){ readSomething = true; error.append(buffer, 0, read); } } // Check the exit status only we haven"t read anything, // if something has been read, the process is obviously not dead yet. if (!readSomething){ try { this.status = process.exitValue(); done = true; } catch (IllegalThreadStateException itx){ // Exit status not ready yet. // Give the process a little breathing room. try { Thread.sleep(100); } catch (InterruptedException ix){ process.destroy(); throw new IOException("Interrupted - processes killed"); } } } } this.output = output.toString(); this.error = error.toString(); } /** * The output of the job that ran. * * @since ostermillerutils 1.06.00 */ private String output; /** * Get the output of the job that ran. * * @return Everything the executed process wrote to its standard output as a String. * * @since ostermillerutils 1.06.00 */ public String getOutput(){ return output; } /** * The error output of the job that ran. * * @since ostermillerutils 1.06.00 */ private String error; /** * Get the error output of the job that ran. * * @return Everything the executed process wrote to its standard error as a String. * * @since ostermillerutils 1.06.00 */ public String getError(){ return error; } /** * The status of the job that ran. * * @since ostermillerutils 1.06.00 */ private int status; /** * Get the status of the job that ran. * * @return exit status of the executed process, by convention, the value 0 indicates normal termination. * * @since ostermillerutils 1.06.00 */ public int getStatus(){ return status; } } </source>
Launches a process, redirecting the output of that sub-process to the output of this (the parent) process.
<source lang="java">
import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; /**
* Launches a process, redirecting the output of that sub-process to the output * of this (the parent) process. * * @author Klaas Waslander */
public final class ProcessLauncher {
/** the logger for this class */ private final static Logger LOGGER = Logger.getLogger(ProcessLauncher.class.getName()); private String commandLine; private String[] commandArray; private File baseDir; private ArrayList listeners = new ArrayList(1); private Process subProcess; private boolean finished = false; StringBuffer out = new StringBuffer(); StringBuffer err = new StringBuffer(); /** * Constructs new process launcher with the given command line. */ public ProcessLauncher(String commandLine) { this(commandLine, null); } public ProcessLauncher(String commandLine, File baseDir) { this.rumandLine = commandLine; this.baseDir = baseDir; } /** * Constructs new process launcher with the given command array. */ public ProcessLauncher(String[] commandArray) { this(commandArray, null); } public ProcessLauncher(String[] commandArray, File baseDir) { this.rumandArray = commandArray; this.baseDir = baseDir; } /** * Constructs new process launcher with the given command element list. */ public ProcessLauncher(ArrayList commandList) { this(commandList, null); } public ProcessLauncher(ArrayList commandList, File baseDir) { this(toStringArray(commandList), baseDir); } private static String[] toStringArray(ArrayList list) { String[] result = new String[list.size()]; Iterator iter = list.iterator(); int arrayIndex = 0; while (iter.hasNext()) { result[arrayIndex++] = iter.next().toString(); } return result; } /** * Classes implementing this interface can receive output generated by * processes launched using the ProcessLauncher. */ public interface OutputListener { public void standardOutput(char[] output); public void errorOutput(char[] output); } /** * Add a listener for output from the to-be-launched process. */ public void addOutputListener(OutputListener listener) { this.listeners.add(listener); } /** fire error output event */ private void fireErr(char[] err) { if (this.listeners.isEmpty()) { this.err.append(out); } Iterator iter = this.listeners.iterator(); while (iter.hasNext()) { ((OutputListener) iter.next()).errorOutput(err); } } /** fire standard output event */ private void fireOut(char[] out) { if (this.listeners.isEmpty()) { this.out.append(out); } Iterator iter = this.listeners.iterator(); while (iter.hasNext()) { ((OutputListener) iter.next()).standardOutput(out); } } /** * Get standard output, in case no listeners were registered - never returns * null. */ public String getStandardOutput() { if (!this.listeners.isEmpty()) { throw new IllegalStateException( "Cannot get standard output, because outputlisteners have been registered."); } return this.out.toString(); } /** * Get error output, in case no listeners were registered - never returns * null. */ public String getErrorOutput() { if (!this.listeners.isEmpty()) { throw new IllegalStateException( "Cannot get error output, because outputlisteners have been registered."); } return this.err.toString(); } /** * Get the commandline that is used to launch the process. */ public String getCommandLine() { String usedCommand = this.rumandLine; if (this.rumandLine == null && this.rumandArray != null) { usedCommand = ""; for (int i = 0; i < this.rumandArray.length; i++) { if (i > 0) { usedCommand += " "; } usedCommand += this.rumandArray[i]; } } return usedCommand; } /** * Check whether execution has finished. */ public boolean hasFinished() { return finished; } /** * Launches the process, and blocks until that process completes execution. * * @throws CommandNotExistsException * If the command could not be executed because it does not exist */ public int launch() throws CommandNotExistsException { this.err.setLength(0); this.out.setLength(0); BackgroundPrinter stdout = null; BackgroundPrinter stderr = null; try { if (this.rumandArray != null) { this.subProcess = Runtime.getRuntime().exec(this.rumandArray, null, this.baseDir); } else { this.subProcess = Runtime.getRuntime().exec(this.rumandLine, null, this.baseDir); } stdout = new BackgroundPrinter(subProcess.getInputStream(), false); stderr = new BackgroundPrinter(subProcess.getErrorStream(), true); stdout.start(); stderr.start(); // kill process and wait max 10 seconds for output to complete int exitValue = this.subProcess.waitFor(); stdout.join(10000); stderr.join(10000); /* * if (exitValue != 0) { LOGGER.fine("WARNING: exit value " + exitValue + " * for command \"" + getCommandLine() + "\""); } */ return exitValue; } catch (IOException ioe) { // usually caused if the command does not exist at all throw new CommandNotExistsException("Command probably does not exist: " + ioe); } catch (Exception e) { LOGGER .log(Level.SEVERE, "Exception while running/launching \"" + getCommandLine() + "\".", e); } finally { if (this.subProcess != null) { this.subProcess.destroy(); this.subProcess = null; } if (stdout != null) { stdout.close(); } if (stderr != null) { stderr.close(); } this.finished = true; } return -1; } /** * Tries to abort the currently running process. */ public void abort() { if (this.subProcess != null) { this.subProcess.destroy(); this.subProcess = null; } } /** * Catches output from a "java.lang.Process" and writes it to either * System.err or System.out. * * @author Klaas Waslander - Sun Java Center */ private class BackgroundPrinter extends Thread { private InputStream in; boolean isErrorOutput; public BackgroundPrinter(InputStream in, boolean isErrorOutput) { this.in = in; this.isErrorOutput = isErrorOutput; } public void run() { try { BufferedReader reader = new BufferedReader(new InputStreamReader(this.in)); // read buffer char[] buf = new char[1024]; // write data to target, until no more data is left to read int numberOfReadBytes; while ((numberOfReadBytes = reader.read(buf)) != -1) { char[] clearedbuf = new char[numberOfReadBytes]; System.arraycopy(buf, 0, clearedbuf, 0, numberOfReadBytes); if (this.isErrorOutput) { fireErr(clearedbuf); } else { fireOut(clearedbuf); } } /* * } catch (IOException ioe) { // ignore this: process has ended, * causing IOException } catch (NullPointerException ioe) { // ignore * this: there was no resulting output */ } catch (Exception e) { LOGGER.log(Level.FINE, "Exception while reading from stream from subprocess.", e); } } public void close() { try { this.in.close(); } catch (Exception e) { LOGGER.log(Level.WARNING, "Closing background stream for launched process caused exception.", e); } } } /** * Exception that is thrown when a command could not be executed because it * (probably) does not exist at all. * * @author Klaas Waslander */ public static class CommandNotExistsException extends RuntimeException { /** * Construct a new exception for a command that does not exist. * * @param msg * The message for this exception. */ public CommandNotExistsException(String msg) { super(msg); } }
}
</source>
ProcessBuilder Demo
<source lang="java">
class MainClass {
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."); } }
}
</source>
Process Watcher
<source lang="java">
/**
* * vpc-commons library * * Description: <start><end> * * Copyright (C) 2006-2008 Taha BEN SALAH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /**
**
* Process process = Runtime.getRuntime().exec(new String[]{"/bin/java","-version"}, null, new File(".")); * ProcessWatcher w = new ProcessWatcher(process, new ProcessWatcherHandler() { * public void started(Process process) { * System.out.println("Prcess started"); * } * * public void stdout(Process process, String line) { * System.out.println(line); * } * * public void stderr(Process process, String line) { * System.err.println(line); * } * * public void ended(Process process, int value) { * System.out.println("Process Shutdown. Exit Value :" + value); * } * * public void error(Process process, Throwable th) { * System.err.println(th); * } * }); * w.start(); *
* @author Taha Ben Salah (taha.bensalah@gmail.ru) * @creationtime 27 juin 2007 12:08:13 */
public class ProcessWatcher {
private Process process; private Thread end; private Thread out; private Thread err; private int result; private boolean stopped=false; private ProcessWatcherHandler handler;
public ProcessWatcher(Process theProcess, ProcessWatcherHandler theHandler) { this.process = theProcess; this.handler = theHandler; end=new Thread(){ @Override public void run() { try { result = process.waitFor(); handler.ended(process,result); } catch (Throwable e) { handler.error(process,e); } finally{ stopped=true; } } }; out=new Thread(){ @Override public void run() { String read; BufferedReader in=new BufferedReader(new InputStreamReader(process.getInputStream())); while (!stopped) { try { read = in.readLine(); if (read == null) { break; } handler.stdout(process,read); } catch (Throwable e) { handler.error(process,e); break; } } } }; err=new Thread(){ @Override public void run() { String read; BufferedReader in=null; try { in = new BufferedReader(new InputStreamReader(process.getErrorStream())); while (!stopped) { try { read = in.readLine(); if (read == null) { break; } handler.stderr(process,read); } catch (Throwable e) { handler.error(process,e); break; } } } catch(Throwable e) { handler.error(process,e); } finally { if (in!=null) { try { in.close(); } catch (IOException e) { handler.error(process,e); } } } } }; } public void start(){ handler.started(process); end.start(); out.start(); err.start(); } public int waitfor(){ while(!stopped){ Thread.yield(); } return result; }
} /**
* * vpc-commons library * * Description: <start><end> * * Copyright (C) 2006-2008 Taha BEN SALAH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */
/**
* @author Taha Ben Salah (taha.bensalah@gmail.ru) * @creationtime 27 juin 2007 12:08:46 */ interface ProcessWatcherHandler { public void started(Process process); public void stdout(Process process,String line); public void stderr(Process process,String line); public void ended(Process process,int value); public void error(Process process,Throwable th);
}
</source>
Use of ProcessBuilder that duplicates the functions of the DoRuntime example:
<source lang="java">
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Arrays; public class Main {
public static void main(String args[]) throws IOException { Process process = new ProcessBuilder(args).start(); InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line; System.out.printf("Output of running %s is:", Arrays.toString(args)); while ((line = br.readLine()) != null) { System.out.println(line); } }
}
</source>
Use ProcessBuilder.environment()
<source lang="java">
/*
* Copyright (c) 1995 - 2008 Sun Microsystems, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Sun Microsystems nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
import java.util.Map; public class PassEnv {
public static void main(String[] args) throws java.io.IOException { System.out.println(System.getProperty("java.class.path")); ProcessBuilder pb = new ProcessBuilder("java", "Env", "DRAGONBALLS"); Map<String, String> env = pb.environment(); env.put("DRAGONBALLS", "7"); pb.start(); }
}
</source>