java.lang.ProcessBuilder Example

In this article, we are going to discuss the ProcessBuilder API. But first, lets understand the use of ProcessBuilder. One can guess by its name that it has something to do with building processes.

ProcessBuilder can be used to help create operating system processes. Before JDK 5.0, the only way to start a process and execute it, was to use the exec() method of the java.lang.Runtime class. Since JDK 5.0, ProcessBuilder has added a new way of executing a command in a separate process.

The major improvement being that, it also acts as a holder for all those attributes that influence the process.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial3>

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

and many more ....

 

1. ProcessBuilder API

It has methods to configure the process and a start() method to create a new Process instance. One can re-configure the process attributes, including the process command itself and call start() to create multiple sub processes. So the steps to run system commands is simple:

  1. Construct a ProcessBuilder object passing commands
  2. Configure and start ProcessBuilder object
  3. Assign the results to a Process object
  4. Read the standard output and standard error

Before I show you the examples, it is important that I brief you about the methods that help us to configure the process builder.

2. ProcessBuilder Example

In this example, I will run the echo command. The echo command and the argument values both are passed to ProcessBuilder‘s constructor. Once ProcessBuilder object is created, we start the process using start(), the result of which, is a Process object. We then wait for the process to finish using process.waitFor(). Once the process is finished, the returned value tells us whether the process was successful. We then call process.getInputStream() to read the process output and print its contents.

ProcessBuilderExample:

package com.javacodegeeks.process;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class ProcessBuilderExample {
	public static void main(String[] args) throws InterruptedException,
			IOException {
		ProcessBuilder pb = new ProcessBuilder("echo", "This is ProcessBuilder Example from JCG");
		System.out.println("Run echo command");
		Process process = pb.start();
		int errCode = process.waitFor();
		System.out.println("Echo command executed, any errors? " + (errCode == 0 ? "No" : "Yes"));
		System.out.println("Echo Output:\n" + output(process.getInputStream()));	
	}
	private static String output(InputStream inputStream) throws IOException {
		StringBuilder sb = new StringBuilder();
		BufferedReader br = null;
		try {
			br = new BufferedReader(new InputStreamReader(inputStream));
			String line = null;
			while ((line = br.readLine()) != null) {
				sb.append(line + System.getProperty("line.separator"));
			}
		} finally {
			br.close();
		}
		return sb.toString();
	}
}

Output:

Run echo command
Echo command executed, any errors? No
Echo Output:
This is ProcessBuilder Example from JCG

3. Handle reading of sub-process output in a separate thread

In this example, I will show you how to handle sub-process IO in a separate thread so that it doesn’t cause blocking of the sub-process. We will also see you how to change the working directory.

The process to be launched is the command prompt, so we create ProcessBuilder passing cmd.exe. The input to the command is /C dir & echo example of & echo working dir. It prints the current directory and then echoes “example of” and “working dir”.

Before we start the process, I would like the working directory to be changed to src so that it prints the source directory. We can do this by calling directory(File) and passing on the File reference of the working directory.

I then start the process and call getInputStream() on the returned Process object, to get its input stream. Using the input stream we can read the process output, but instead of doing it in the same thread, I handle it in a separate thread so that any chances of it blocking the sub-process are minimized.

ProcessBuilderMultipleCommandsExample:

package com.javacodegeeks.process;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;
public class ProcessBuilderMultipleCommandsExample {
	public static void main(String[] args) throws InterruptedException,
			IOException {
		// multiple commands
		// /C Carries out the command specified by string and then terminates
		ProcessBuilder pb = new ProcessBuilder("cmd.exe",
				"/C dir & echo example of & echo working dir");
		pb.directory(new File("src"));
		Process process = pb.start();
		IOThreadHandler outputHandler = new IOThreadHandler(
				process.getInputStream());
		outputHandler.start();
		process.waitFor();
		System.out.println(outputHandler.getOutput());
	}
	private static class IOThreadHandler extends Thread {
		private InputStream inputStream;
		private StringBuilder output = new StringBuilder();
		IOThreadHandler(InputStream inputStream) {
			this.inputStream = inputStream;
		}
		public void run() {
			Scanner br = null;
			try {
				br = new Scanner(new InputStreamReader(inputStream));
				String line = null;
				while (br.hasNextLine()) {
					line = br.nextLine();
					output.append(line
							+ System.getProperty("line.separator"));
				}
			} finally {
				br.close();
			}
		}
		public StringBuilder getOutput() {
			return output;
		}
	}
}

Output:

 Volume in drive C is OSDisk
 Volume Serial Number is 04FF-2626
 Directory of C:\javacodegeeks_ws\processBuilder\src
11-02-2015  10:27              .
11-02-2015  10:27              ..
10-02-2015  10:54              com
11-02-2015  11:23              resources
               0 File(s)              0 bytes
               4 Dir(s)  37,247,864,832 bytes free
example of 
working dir

4. How to redirect input and output

In this example, I want to demonstrate how to redirect input and output of the process. At the end of the example, you will learn the below mentioned:

  1. Adding new environment variable.
  2. Redirecting the process output and error to files.
  3. Merging error with the process output.
  4. Redirecting process input source to a file so that the command process can read the dos commands directly from the file.

I want to run a set of commands including a ping command. These commands are in a file called ping.bat.

The commands make use of a couple of environment variables. The echo command contains an environment variable called name and the ping command contains an environment variable called echoCount to control the count of echo requests. When we call environment() on the ProcessBuilder object, we get its environment in the form of a Map. We can then add our new environment variables to this Map object.

Now lets come to redirecting IO. In order to direct the input and output of the process to the files, we create new file instances to represent the process output and error. We next pass the respective File instances to the redirectOutput and redirectError methods. Next, we start the process, wait for it to finish and then print the file contents.

Suppose instead of having a separate error file, we want the error output to be merged to the same file which is meant for the process output, we just need to set redirectErrorStream to true. So in case of any errors, the error output will be merged to the process output file.

Finally, I will show how, even an input source of sub-process can be re-directed. In our example, I do it for the command sub-process so that it can read the DOS commands directly from the file itself. To demonstrate this, I create a ProcessBuilder object using the cmd string. I then call redirectInput(new File("src/resources/ping.bat")) so that the input source of command process becomes the ping.bat file itself.

ping.bat

echo Run %name%
mkdir "src/resources/test"
ping.exe -n %echoCount% 127.0.0.1

ProcessBuilderRedirectIOExample:

package com.javacodegeeks.process;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Map;
import org.omg.CORBA.Environment;
public class ProcessBuilderRedirectIOExample {
	public static void main(String[] args) throws InterruptedException,
			IOException {
		ProcessBuilder pb = new ProcessBuilder("src/resources/ping.bat");
		System.out.println("Configure parameters");
		Map<String, String> env = pb.environment();
		env.put("name", "ping command");
		env.put("echoCount", "2");
		System.out.println("Redirect output and error to file");
		File outputFile = new File("src/resources/PingLog.txt");
		File errorFile = new File("src/resources/PingErrLog.txt");
		pb.redirectOutput(outputFile);
		pb.redirectError(errorFile);
		// echo Run %name%
		// mkdir "test"
		// ping.exe -n %echoCount% 127.0.0.1
		Process process = pb.start();
		process.waitFor();
		// re-run again, should fail as test dir now already exists
		System.out.println("\nRerun again so that the mkdir command throws error");
		process = pb.start();
		process.waitFor();
		System.out.println("\nPrint Output:");
		printFile(outputFile);
		System.out.println("\nPrint Error:");
		printFile(errorFile);
		
		System.out.println("\nRedirect error and run again so that error is redirected to output file");
		pb.redirectErrorStream(true);
		File commonOutputFile = new File("src/resources/PingCommonLog.txt");
		pb.redirectOutput(commonOutputFile);
		process = pb.start();
		process.waitFor();
		
		System.out.println("\nPrint Common Output:");
		printFile(commonOutputFile);
		
		System.out.println("\nRedirect input source to a file");
		pb = new ProcessBuilder("cmd");
		pb.environment().putAll(env);
		pb.inheritIO();
		pb.redirectInput(new File("src/resources/ping.bat"));
		process = pb.start();
		process.waitFor();
	}
	
	private static void printFile(File file) throws IOException {
		System.out.println("*********************************");
		FileReader fr = new FileReader(file);
		BufferedReader br = new BufferedReader(fr);
		String line;
		while ((line = br.readLine()) != null) {
			System.out.println(line);
		}
		br.close();
		fr.close();
		System.out.println("*********************************");
	}
}

Output:

Configure parameters
Redirect output and error to file
Rerun again so that the mkdir command throws error
Print Output:
*********************************
Run ping command
Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Ping statistics for 127.0.0.1:
    Packets: Sent = 2, Received = 2, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms
*********************************
Print Error:
*********************************
A subdirectory or file src/resources/test already exists.
*********************************
Redirect error and run again so that error is redirected to output file
Print Common Output:
*********************************
Run ping command
A subdirectory or file src/resources/test already exists.
Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time@ECHO OFF
echo Run %name%
Run ping command
mkdir "src/resources/test"
More? A subdirectory or file src/resources/test already exists.

5. Example of inheritIO

In this example, I call inheritIO to redirect the sub-process IO to the standard IO of the current process. After ProcessBuilder is created, I call on inheritIO so that the output of sub-process gets printed to the console window.

ProcessBuilderInheritIOExample:

package com.javacodegeeks.process;
import java.io.IOException;
public class ProcessBuilderInheritIOExample {
	public static void main(String[] args) throws InterruptedException,
			IOException {
		ProcessBuilder pb = new ProcessBuilder("echo", "Hello JCG\nThis is ProcessBuilder Example");
		//inherit IO
		pb.inheritIO();
		System.out.println("Run Echo command with inheritIO set");
		Process process = pb.start();
		process.waitFor();
	}
}

Output:

Run Echo command with inheritIO set
Hello JCG
This is ProcessBuilder Example

Download the Eclipse Project

In this article, I have shown you various examples ofthe ProcessBuilder class.

Download
You can download the full source code of this example here: processBuilder.zip
Exit mobile version