5

I'm trying to redirect stdin and stdout of a subprocess in java, eventually i'm going to have the output go to a JTextArea or something.

Here is my current code,

Process cmd = Runtime.getRuntime().exec("cmd.exe");

cmd.getOutputStream().write("echo Hello World".getBytes());
cmd.getOutputStream().flush();

byte[] buffer = new byte[1024];
cmd.getInputStream().read(buffer);
String s = new String(buffer);

System.out.println(s);

The output looks like this:

Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\(Current Directory)>

I'm expecting to see the "Hello World" string outputted. Maybe because the parent process isn't staying alive long enough?

I'd also like to be able to send and receive multiple commands.

Josh
  • 5,264
  • 7
  • 41
  • 80

2 Answers2

10

You've attempted to write to the output stream before you attempt to listen on the input stream, so it makes sense that you're seeing nothing. For this to succeed, you will need to use separate threads for your two streams.

i.e.,

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Scanner;

public class Foo {
   public static void main(String[] args) throws IOException {
      Process cmd = Runtime.getRuntime().exec("cmd.exe");

      final InputStream inStream = cmd.getInputStream();
      new Thread(new Runnable() {
         public void run() {
            InputStreamReader reader = new InputStreamReader(inStream);
            Scanner scan = new Scanner(reader);
            while (scan.hasNextLine()) {
               System.out.println(scan.nextLine());
            }
         }
      }).start();

      OutputStream outStream = cmd.getOutputStream();
      PrintWriter pWriter = new PrintWriter(outStream);
      pWriter.println("echo Hello World");
      pWriter.flush();
      pWriter.close();
   }
}

And you really shouldn't ignore the error stream either but instead should gobble it, since ignoring it will sometimes fry your process as it may run out of buffer space.

Hovercraft Full Of Eels
  • 276,051
  • 23
  • 238
  • 346
  • 1
    @Hovevercraft: you say that he's “you attempted to write to the output stream before you attempt to listen on the input stream, so it makes sense that you're seeing nothing”. I don't understand why reading *after* the command was written would lead to a short read. In fact, you say "seeing nothing", but at least he's seeing `cmd.exe`'s banner and prompt. I have the impression that if he read again, he would see the rest of it. What I'm missing? – Marcos Dione Aug 29 '16 at 13:13
6

Nowadays Runtime.getRuntime().exec() is deprecated (for all practical purposes). Better use the ProcessBuilder class; in particular, its start() method will return a Process object with methods for accessing the stdin and stdout streams, which can be redirected wherever you need them. Take a look at this post for further details.

Community
  • 1
  • 1
Óscar López
  • 215,818
  • 33
  • 288
  • 367