ProcessBuilder BufferedReader read() 阻塞
ProcessBuilder BufferedReader read() blocking
我正在使用 ProcessBuilder
到 运行 我们正在使用的命令行工具。在 运行 期间,该工具会问 2 yes/no 个问题,所以通常我会回答 'y' 两次,然后每次都按回车键。我的问题是,当从 cmd 运行ning 时,该工具总是完成它的 运行,但是当我通过我的 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
备选方案包括;写入文件错误,或在另一个线程中读取它。
我正在使用 ProcessBuilder
到 运行 我们正在使用的命令行工具。在 运行 期间,该工具会问 2 yes/no 个问题,所以通常我会回答 'y' 两次,然后每次都按回车键。我的问题是,当从 cmd 运行ning 时,该工具总是完成它的 运行,但是当我通过我的 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
备选方案包括;写入文件错误,或在另一个线程中读取它。