A difficult aspect is the concurrent handling of standard and error output
of a process and the exit status of the process. The process may be generating both
output streams and may exit shortly after generating output.
The default use of pipes connecting child process output is subject to buffer size
limitations, typically in the operating system. The parent process should consume
the generated stream output quickly enough or risk blocking the child process.
Keeping up with both stdout and stderr typically requires the complexity of
separate threads or non-blocking reads polling both streams and the exit status.
Typically, only the process' standard output is handled directly.
Only in the case of failure is stderr needed or examined.
Pipe based handling of output, with limited internal buffering, necessitates concurrently
handling stdout and stderr, usually with separate threads and synchronization
to avoid deadlock and loss of output. Increasing the buffering to hold all
the expected output of the process can significantly simplify application code.
To simplify processing of stdout and stderr, ProcessBuilder adds a redirection mode to buffer the streams.
The amount of buffering is large (10's of megabytes) depending on the resources of the host system.
The output from the process is accessible via existing `getInputStream()` and `getErrorStream()` methods
and is retained until the Process instance is no longer referenced.
Failing to read the streams will not block process' execution.
As long as the process is alive, its output, if any, can be read as it is generated.
It is anticipated that the output will be buffered in temporary files;
the details may depend on the operating system.
To enable full buffering ProcessBuilder.Redirect adds:
```
public class ProcessBuilder {
public static class Redirect {
/**
* Indicates that subprocess output will be buffered.
*/
public static final Redirect BUFFERED = new Redirect() {...}
/**
* The type of a Redirect.
*/
public enum Type {
..., BUFFERED, ...
}
}
```
An Example:
The standard and error output are fully buffered and can be read whenever they are needed without blocking.
```
ProcessBuilder pb = new ProcessBuilder(args);
pb.redirectOutput(ProcessBuilder.Redirect.BUFFERED);
pb.redirectError(ProcessBuilder.Redirect.BUFFERED);
try {
Process p = pb.start();
try (InputStream is = p.getInputStream()) {
// read stdout from process
}
int status = p.waitFor();
if (status != 0) {
try (InputStream err = p.getErrorStream()) {
// read error output from process
}
}
} catch ...
```