Lawrence Park
Lawrence Park

Reputation:

Java reading standard output from an external program using inputstream

I am trying to develop a class that reads the standard output of an external program(using an instance of Process, Runtime.getRuntime().exec(cmdLine, env, dir)). The program takes user inputs during the process, and would not proceed until a valid input is given; this seems to be causing a problem in the way I am trying to read its output:

    egm.execute(); // run external the program with specified arguments
    BufferedInputStream stdout = new BufferedInputStream(egm.getInputStream());
    BufferedInputStream stderr = new BufferedInputStream(egm.getErrorStream());
    BufferedOutputStream stdin = new BufferedOutputStream(egm.getOutputStream());



    int c; //standard output input stream
    int e; //standadr error input stream

    while((c=stdout.read()) != -1) //<-- the Java class stops here, waiting for input? 
    {
        egm.processStdOutStream((char)c); 
    }
    while((e=stderr.read()) != -1)
    {
        egm.processStdErrStream((char)e);
    }
    //...

How can I fix this so that the program takes in a valid input and proceed? Any help resolving this problem will be great!

Upvotes: 4

Views: 9924

Answers (5)

thoni56
thoni56

Reputation: 3335

For the benefit of others looking for solutions to this type of problem I just want to add that I had a very similar problem. But in my case the program was also waiting for a single line of input. So there need to be three threads involved to asynchronously handle all three channels.

Without writing to the output (i.e. the stdin of the executing program) caused the input (i.e. the output from the executing program) not to be captured completely. Writing to it hanged the process.

The solution was the three words by Jon Skeet: "and flush it". After adding the flush, no hang. Thanks!

Upvotes: 0

Brian Agnew
Brian Agnew

Reputation: 272317

You have to consume both the program's stdout and stderr concurrently to avoid blocking scenarios.

See this article for more info, and in particular note the StreamGobbler mechanism that captures stdout/err in separate threads. This is essential to prevent blocking and is the source of numerous errors if you don't do it properly!

Upvotes: 7

Clint
Clint

Reputation: 9058

In this situation you should have separate Threads reading InputStream and ErrStream.

Also you may want to do something like:

public void run() {
  while( iShouldStillBeRunning ) {
       int c;
       while( stdout.available() > 0 && ((c=stdout.read()) != -1)) {
         egm.processStdOutStream((char)c);
       }

     Thread.sleep(100);
  }
}

Because you will get blocked on stdout.read() until there is input.

Upvotes: 2

dj_segfault
dj_segfault

Reputation: 12449

You're not saying in your question what is actually happening when you try to run this. Please update with a detailed description of what happens, and what you would expect to happen instead. Bonus points for telling us what the command is.

Also, is this UNIX/Linux or Windows? If this is UNIX/Linux (or some other POSIX platform), the program may be looking for input on /dev/console instead of /dev/stdin for security reasons.

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1501163

For one thing, this may block if it's writing to the error stream and has exhausted the buffer - you're not reading from the error stream until the output stream has completely finished.

Next, you say it takes user input during the process - are you giving it any user input by writing to stdin? If it's waiting for input, you should write to stdin appropriately, and flush it.

Upvotes: 1

Related Questions