如何强制 java OutputStreamWriter 实际写入单个字节?
How to force java OutputStreamWriter to actually write a single byte?
我正在尝试 运行 来自 Java 的简单回显程序(使用 ProcessBuilder
),有一个无限循环,我从用户那里获取输入(使用 Scanner
).然后我使用 OutputStreamWriter
将它写入进程的标准输入,我希望看到相同的字符串通过标准输出回显,但它不会,除非我关闭流(我不想这样做)或我写了一个长字符串。即使在调用 flush 时,如果字符串很短(比如 1 个字符),它也不起作用。
即使是单个字符(短)字符串,我们如何强制刷新?
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);
}
编辑 3/18:我已经尝试 windows sysinternals 工具来跟踪写系统调用,看起来我的猜测确实是正确的,除非它是一个长字符串(或者除非你关闭流)。
编辑 3/19:我发现了这个:Does fgets() locks stdout preventing printf 这让事情变得更加有趣。
问题出在与 a.exe
的交互中。
a.exe
使用 fgets
。它会在读取 (n-1) 个字符、读取换行符或到达文件末尾时停止,以先到者为准。
您没有将新行推送到 a.exe
,因此 fgets
只能以 EOF 完成,这在您关闭流时发生。
您可以从 Java 推入一个行尾,或者您可以在 C 端使用另一个读取函数。
要推送行尾,您可以使用:
writer.write(System.lineSeparator());
参见:https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm
由于这个问题
问题[终于]解决了
Does fgets() locks stdout preventing printf
所以问题实际上不是 java 的错,它是 windows 的特性之一,这里我已经将流连接到 stdin 和 stdout,虽然我没有关闭 stdin,但它确实不写入标准输出。
所以解决方案:要么 1) 在 "a.exe" 端刷新标准输出。或者 2) 只是不要同时使用这两个流。例如,在 "a.exe" 端,而不是 stdout,写入文件,而在 java 端,从该文件消费。
如果您有权访问 "a.exe",(1) 是更好的选择,但这可能是您无权访问的外部程序。
我正在尝试 运行 来自 Java 的简单回显程序(使用 ProcessBuilder
),有一个无限循环,我从用户那里获取输入(使用 Scanner
).然后我使用 OutputStreamWriter
将它写入进程的标准输入,我希望看到相同的字符串通过标准输出回显,但它不会,除非我关闭流(我不想这样做)或我写了一个长字符串。即使在调用 flush 时,如果字符串很短(比如 1 个字符),它也不起作用。
即使是单个字符(短)字符串,我们如何强制刷新?
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);
}
编辑 3/18:我已经尝试 windows sysinternals 工具来跟踪写系统调用,看起来我的猜测确实是正确的,除非它是一个长字符串(或者除非你关闭流)。
编辑 3/19:我发现了这个:Does fgets() locks stdout preventing printf 这让事情变得更加有趣。
问题出在与 a.exe
的交互中。
a.exe
使用 fgets
。它会在读取 (n-1) 个字符、读取换行符或到达文件末尾时停止,以先到者为准。
您没有将新行推送到 a.exe
,因此 fgets
只能以 EOF 完成,这在您关闭流时发生。
您可以从 Java 推入一个行尾,或者您可以在 C 端使用另一个读取函数。
要推送行尾,您可以使用:
writer.write(System.lineSeparator());
参见:https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm
由于这个问题
问题[终于]解决了
Does fgets() locks stdout preventing printf
所以问题实际上不是 java 的错,它是 windows 的特性之一,这里我已经将流连接到 stdin 和 stdout,虽然我没有关闭 stdin,但它确实不写入标准输出。
所以解决方案:要么 1) 在 "a.exe" 端刷新标准输出。或者 2) 只是不要同时使用这两个流。例如,在 "a.exe" 端,而不是 stdout,写入文件,而在 java 端,从该文件消费。
如果您有权访问 "a.exe",(1) 是更好的选择,但这可能是您无权访问的外部程序。