tags:

views:

155

answers:

3

I have written the java code below, which executes another java program named "Newsworthy_RB".

Newsworthy_RB.java contains both the System.out.printlln() and System.err.println() statements.

I want both the outputs to be printed in the command prompt console.

What has to be done inorder to obtain the same.

The below program just prints the out.println() statements and not the err.println() statements.

Kindly let me know whether the code below will function as i expect?

command = "java -cp .:../sqljdbc.jar SetHash Newsworthy_RB";
Process child1 = Runtime.getRuntime().exec(command);
InputStream in1 = child1.getErrorStream();
InputStream in2 = child2.getInputStream();
while ((c = in1.read()) != -1 || (c = in2.read()) != -1) {
        System.out.print((char)c);
    }
+7  A: 

You need to pipe the output of both streams in a separate threads. Example code from here:

Process p = Runtime.getRuntime().exec(cmd.array());
copyInThread(p.getInputStream(), System.out);
copyInThread(p.getErrorStream(), System.err);
p.waitFor();
return p.exitValue();

private void copyInThread(final InputStream in, final OutputStream out) {
    new Thread() {
        public void run() {
            try {
                while (true) {
                    int x = in.read();
                    if (x < 0) {
                        return;
                    }
                    if (out != null) {
                        out.write(x);
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    } .start();
}
Thomas Mueller
Thanks for your response Mueller. I have updated my question. Please let me know will that work or not?
LGAP
From the docs of `Runtime`: "ProcessBuilder.start() is now the preferred way to start a process with a modified environment.". I recommend using `ProcessBuilder.redirectErrorStream`. (See my answer.)
aioobe
@aioobe: You are right! I didn't know about ProcessBuilder.
Thomas Mueller
@LGAP: The problem is the threads (as aioobe alreay wrote)
Thomas Mueller
+1  A: 

There are two methods in the Process object: getErrorStream and getInputStream. Currently, your program is only listening to one. You'll want it to listen to both.

Dante617
+6  A: 

First of all, the preferred way of starting external programs is through ProcessBuilder. It is even mentioned in the docs for Runtime:

ProcessBuilder.start() is now the preferred way to start a process with a modified environment.

In ProcessBuilder you have a very convenient method called redirectErrorStream:

Sets this process builder's redirectErrorStream property.

If this property is true, then any error output generated by subprocesses subsequently started by this object's start() method will be merged with the standard output, so that both can be read using the Process.getInputStream() method. This makes it easier to correlate error messages with the corresponding output. The initial value is false.

A complete example of how to output both standard error and standard out:

import java.io.*;

public class Test {
    public static void main(String... args) throws IOException {

        ProcessBuilder pb =
                new ProcessBuilder("java", "-cp", "yourClassPath", "HelloWorld");

        pb.redirectErrorStream(true);
        Process proc = pb.start();

        Reader reader = new InputStreamReader(proc.getInputStream());
        int ch;
        while ((ch = reader.read()) != -1)
            System.out.print((char) ch);
        reader.close();
    }
}

Response to your update: No, the code with

while ((c = in1.read()) != -1 || (c = in2.read()) != -1)

will not work, since read() is a blocking method and you only have one thread. Your only option is to use one thread per input-stream, or, (preferrably) merge the two input-streams into one, using ProcessBuilder.redirectErrorStream.

aioobe
I just love the kind of explanation. Thanks a lot for your response. But for the time being, kindly let me know whether the modification that I have done in my question will work or not?
LGAP
I will definitely implement ProcessBuilder concepts in my future procedings.
LGAP
Also let me know `ProcessBuilder pb = new ProcessBuilder("java", "HelloWorld");` how to mention the classpath of the program in this statement?
LGAP
I mean the classpath for the Helloworld java program.
LGAP
Updated my answer. Added a response to your code-snippet, and demonstrated class-path.
aioobe
@aioobe Thanks a lot :-) Am clear now
LGAP