tags:

views:

1062

answers:

6

Hello, 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!

+1  A: 

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.

Jon Skeet
A: 

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.

dj_segfault
+1  A: 

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.

Clint
A: 

After reading Jon's response to my question, I realized that I haven't explained the situation right. From the debugging console of my working IDE(Netbeans 6.5.1), I was able to confirm that the class stops at: while((c=stdout.read()) != -1) //<-- the Java class stops here, waiting for input? { egm.processStdOutStream((char)c); } And I am expecting to read the greeting text from the external program in this particular code block. Instead, I get "User program running," from the debugging console... What does this mean?

+3  A: 

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!

Brian Agnew
A: 

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!

Thomas Nilsson