I am trying to run a simple echo program from Java (using ProcessBuilder
), there is an infinite loop in which I get input from user (using Scanner
). Then I use OutputStreamWriter
to write it to stdin of the process, and I expect to see the same string echoed back through the stdout, but it doesn't unless I close the stream (which I do not want to) or I write a long string. ven when calling flush, if the string is short (like, 1 character) it does not work.
How can we force flushing, even for single character (short) strings?
ProcessBuilder pb = new ProcessBuilder(cmd);
Process p = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
OutputStream stdin = p.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(stdin);
Scanner scanner = new Scanner(System.in);
String line;
while (true) {
String input = scanner.nextLine();
if (input.equals("q"))
break;
writer.write(input+"\n");
writer.flush();
// writer.close(); (uncommenting this makes it work once, then throw error)
line = br.readLine();
System.out.println(line);
}
Edit 3/18: I have tried windows sysinternals tools to track the write syscalls and it indeed looks like my guess is correct, the flush does not work unless it is a long string (or unless you close the stream).
Edit 3/19: I found this: Does fgets() locks stdout preventing printf which makes things even more interesting.
The question is [finally] solved thanks to this question:
Does fgets() locks stdout preventing printf
So the problem was not actually java's fault, it is one of the idiosynchrasies of windows, here as I have hooked up streams to both stdin and stdout and while I have not closed stdin, it does not write to stdout.
So the solution: Either 1) flush stdout on "a.exe" side. OR 2) just don't use both streams. For example, on "a.exe" side, instead of stdout, write to file, and on java side consume from that file.
(1) is the better option IF you have access to "a.exe" but this might be an external program you have no access to.