Reputation:
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
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
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
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
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
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