我正在使用ProcessBuilder
运行我们正在使用的命令行工具。在运行期间,该工具会询问2个“是/否”问题,因此通常我会回答“ y”两次,然后每次都按Enter键。我的问题是,从cmd运行该工具时,它总是会完成运行,但是当我通过Java代码运行该工具时,它有时会工作,有时会卡在while ((n = op.read(buffer)) != -1)
上(使用相同的输入)。
这是我的代码。难道我做错了什么?我想念什么?谢谢。
List<String> processArgs = new ArrayList<>();
processArgs.add(0, "java");
processArgs.add(1, "-jar");
processArgs.add(2, JAR_PATH);
processArgs.add(3, "-put");
processArgs.addAll(args);
try
{
// run tool with put
ProcessBuilder pb = new ProcessBuilder(processArgs);
pb.directory(new File("src\\temp"));
pb.redirectErrorStream(true);
Process p = pb.start();
// write 'y' to the tool's stdin.
String answer = "y" + System.getProperty("line.separator");
// yes to first question
p.getOutputStream().write(answer.getBytes());
p.getOutputStream().flush();
// read tool's process stdout
this.op = new BufferedReader(new InputStreamReader(p.getInputStream()));
StringWriter sw = new StringWriter();
int n = 0;
boolean answered = false;
char[] buffer = new char[BUFFER_SIZE];
while ((n = op.read(buffer)) != -1)
{
sw.write(buffer, 0, n);
if (sw.toString().contains("second question") && !answered)
{
// yes to second question
p.getOutputStream().write(answer.getBytes());
p.getOutputStream().flush();
answered = true;
}
}
stdout = sw.toString();
exitCode = p.waitFor();
}
catch (IOException | InterruptedException e)
{
throw new ToolException("process had an exception:\n" + e.getMessage());
}
更新:
我更改了代码并添加了
pb.redirectErrorStream(true)
,但是现在该过程仍然在op.read(buffer)
上被阻止。当我调试时,即使我在输出流中写了两次“ y”,它似乎也卡在了第二个问题上。我使用getOutputStream()
的方式不正确吗?第二次更新:
第二个问题没有得到第二个“ y”作为答案,它导致流程等待输入。我更改了代码,因此我将显示将输入插入子流程输出流的正确方法。
最佳答案
输出和错误流被缓冲。当缓冲区填满时,程序停止等待您读取它。但是,您只能先读取输出,因此,如果错误流满了,您将陷入死锁。
一种简单的解决方案是将错误重定向到输出,这样您就只能读取一个流。即
pb.redirectErrorStream(true);
根据文档https://docs.oracle.com/javase/8/docs/api/java/lang/ProcessBuilder.html
替代方案包括;将错误写入文件,或在另一个线程中读取它。
关于java - ProcessBuilder BufferedReader read()阻塞,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42053481/