SOLVED:
HovecraftFullOfEels found my mistake. See the comments on his answer below. I was calling run() on a Thread object when I should have been calling start(). In my original program, that meant it blocked on stderr until the program quit and then got stdout all at once.
UPDATE:
As requested, I've produced a minimal example. Here's the producer:
package producer;
public class Producer {
public static void main(String[] args) throws InterruptedException {
for (int i=0; i<10; i++) {
System.out.println(i);
System.out.flush();
Thread.sleep(1000);
}
}
}
Here's the consumer:
package consumer;
import java.io.IOException;
import java.io.InputStream;
public class Consumer {
static class Dumper extends Thread {
InputStream r;
boolean print;
Dumper(InputStream r, boolean print) {
this.r = r;
this.print = print;
}
@Override
public void run() {
int c;
try {
while ((c = r.read()) != -1) {
if (print) System.out.print((char)c);
}
r.close();
} catch (IOException ex) {}
}
}
public static void main(String[] args) throws Exception {
Process p = Runtime.getRuntime().exec("java -jar C:\\Users\\millerti\\Documents\\NetBeansProjects\\Producer\\dist\\Producer.jar");
new Dumper(p.getErrorStream(), false).run();
new Dumper(p.getInputStream(), true).run();
p.waitFor();
}
}
Expected behavior: Since the producer flushes its output and the consumer is completely unbuffered, the consumer should get the producer's output in real time.
Observed behavior: The consumer receives the producer's output all at once only when the producer finished.
Original post:
I'm working with another developer on a Windows application. She has written a C program (which we can modify) that performs a media conversion and prints progress messages (in percentage) to stdout. I am writing a graphical front-end in Java, and I would like my program to capture those messages and update a GUI element.
The relevant C program code looks like this:
printf ("progress_msg: %d%%\n", currentProgress);
fflush(stdout);
In the Java program, I'm using Runtime.getRuntime().exec()
to run the C program and grabbing the raw InputStream objects for C program's stdout and stderr. (The stderr is just being thrown away by another thread.) I'm parsing the stdout stream, looking for those messages (well, I was, using a BufferedReader, but right now, I'm trying to debug this, so I'm talking directly to the low-level InputStream byte source.)
The problem is that although there is no buffering on the Java side (that I know of) and there's an fflush
in the C program, the stdout text appears all at once only when the C program finishes. This is unlike when I run it from the command prompt, where the messages come out gradually as expected.
So clearly, there's some buffering going on. Is the Process facility in Java doing some buffering that I don't know about? If so, is there a way to turn it off? Does fflush(stdout)
in Windows not work in the expected way? What is the proper Windows equivalent?
Thanks.
Note: I have found two related stackoverflows, but they do not answer this question. In particular, we CAN modify the C program, there's no line buffering, and we ARE doing a proper flush (as far as we know). See I want realtime output of my Runtime.getRuntime().exec() and Unbuffered subprocess stdout on windows.