49

I am trying to get the OutputStream of the Process initiated by exec() to the console. How can this be done?

Here is some incomplete code:

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;

public class RuntimeTests
{
    public static void main(String[] args)
    {
        File path = new File("C:\\Dir\\Dir2");
        String command = "cmd /c dir";
        Reader rdr = null;
        PrintStream prtStrm = System.out;
        try
        {
            Runtime terminal = Runtime.getRuntime();

            OutputStream rtm = terminal.exec(command, null, path).getOutputStream();
            prtStrm = new PrintStream(rtm);
            prtStrm.println();
        } 
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
TheWolf
  • 1,675
  • 4
  • 22
  • 34

7 Answers7

117

I recently ran into this problem and just wanted to mention that since java 7 the process builder api has been expanded. This problem can now be solved with:

ProcessBuilder pb = new ProcessBuilder("yourcommand");
pb.redirectOutput(Redirect.INHERIT);
pb.redirectError(Redirect.INHERIT);
Process p = pb.start();
Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • 3
    Perfect and elegant answer. If you can use Java 7, this is absolutely the way to go. – Shane Mar 17 '13 at 08:45
  • 1
    This is the best answer, even though there are good ones above, always try to use the tools that come in the Java toolbox by default. Java 7/8 is an extremely capable and powerful language - with an ever expanding, yet efficient, toolkit. – DtechNet Oct 05 '15 at 15:47
  • I get the following error message with Java 11: "Corrupted STDOUT by directly writing to native stream in forked JVM 1." Is it possible that this solution does not longer work with Java 11? – Erik Nellessen Dec 04 '20 at 12:34
  • Thanks! `pb.redirectOutput(Redirect.INHERIT);` solved a lot of weird quircks for me which was lacking from most other examples online – BitfulByte May 23 '23 at 06:49
  • @BitfulByte happy to have helped, this was literally my first coding task for TipRanks! – Benjamin Gruenbaum May 23 '23 at 07:52
45

I believe this is what you're looking for:

  String line;
  Process p = Runtime.getRuntime().exec(...);
  BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
  while ((line = input.readLine()) != null) {
    System.out.println(line);
  }
  input.close();
Stijn Geukens
  • 15,454
  • 8
  • 66
  • 101
  • 3
    I have a question to your solution: Is there no need to use process.waitFor()? It works also without but why? Does the InputStreamReader wait until the stream ends? – das Keks Apr 04 '13 at 13:57
  • 2
    Yes, API: _If no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown._ – Stijn Geukens Apr 04 '13 at 19:15
  • add a `redirectErrorStream(true)` for completeness. – Jeffrey Blattman Mar 26 '14 at 18:17
  • why inputStream? we're interested in the output, aren't we? – Gavriel May 30 '22 at 10:42
13

I faced the similar problem and I am using the following code.

Process p = Runtime.getRuntime().exec(".....");
p.waitFor();

String line;

BufferedReader error = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while((line = error.readLine()) != null){
    System.out.println(line);
}
error.close();

BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while((line=input.readLine()) != null){
    System.out.println(line);
}

input.close();

OutputStream outputStream = p.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
printStream.println();
printStream.flush();
printStream.close();
Walery Strauch
  • 6,792
  • 8
  • 50
  • 57
samaitra
  • 724
  • 7
  • 7
9

See Benjamin Gruenbaum answer covering ProcessBuilder API available since Java 7.

You need to start a new thread that would read process output happening after Process.waitFor(). Then process output can be copied the console from that thread.

Process.getOutputStream() is actually the input, ie, stdin to the process. Process.getInputStream() and Process.getErrorStream() return InputStream objects which are the stdout and stderr of the process. The InputStreams and OutputStream are from the caller's perspective, which is the opposite of the process's perspective.

The process's output, stdout, is input to the caller, therefore the caller gets a getInputStream() and reads the stdout from it:

Process proc = Runtime.getRuntime().exec(cmdArr, env, cwdir);

InputStreamReader isr = new InputStreamReader(proc.getInputStream());
BufferedReader rdr = new BufferedReader(isr);
while((line = rdr.readLine()) != null) { 
  System.out.println(line);
} 

isr = new InputStreamReader(proc.getErrorStream());
rdr = new BufferedReader(isr);
while((line = rdr.readLine()) != null) { 
  System.out.println(line);
} 
rc = proc.waitFor();  // Wait for the process to complete

Process.getOutputStream() is used for the caller to 'output' data into the stdin of the process. This code could be added after 'proc' is created in the first line of the example above, to send data into stdin of the process:

// Send data to stdin of the process (in development, needs input content)
OutputStream os = proc.getOutputStream();
Bytes content = new Bytes("Hello\nasdf\n adma");
os.write(content.arr, content.off, content.length());
os.close(); // should use try/finally or try/resource

Do the above before reading the output. Remember to close the OutputStream os (either using try/resource or try/finally). So, the process knows that stdin is complete and it can finish processing the info.

Eugene Kuleshov
  • 31,461
  • 5
  • 66
  • 67
5

I know this is a very old question, but a better alternate for the above answers would be

ProcessBuilder builder = new ProcessBuilder(command);
builder.inheritIO();
Process p = builder.start();

From the docs of ProcessBuilder.inheritIO(),

Sets the source and destination for subprocess standard I/O to be the same as those of the current Java process.

Hope this helps someone!

Mohamed Anees A
  • 4,119
  • 1
  • 22
  • 35
2

Try VerboseProcess from jcabi-log:

String output = new VerboseProcess(new ProcessBuilder("foo.bat")).stdout();

The class starts a background thread, listens to the output stream, and logs it.

yegor256
  • 102,010
  • 123
  • 446
  • 597
2

If you can use org.apache.commons.io.IOUTils from commons-io,

System.out.println(IOUtils.toString(process.getInputStream()));
System.err.println(IOUtils.toString(process.getErrorStream()));
radiantRazor
  • 477
  • 3
  • 13