【问题标题】:ProcessBuilder BufferedReader read() blockingProcessBuilder BufferedReader read() 阻塞
【发布时间】:2017-02-05 14:56:54
【问题描述】:

我正在使用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'作为答案,它导致进程等待输入。我更改了代码,因此我将展示将输入插入到子流程输出流的正确方法。

【问题讨论】:

    标签: java bufferedreader processbuilder


    【解决方案1】:

    输出和错误流被缓冲。当缓冲区填满时,程序会停止等待您读取它。但是,您只需要先读取输出,因此如果错误流填满,您就会遇到死锁。

    一个简单的解决方案是将错误重定向到输出,这样您就只有一个流可以读取。即

    pb.redirectErrorStream(true);
    

    根据文档https://docs.oracle.com/javase/8/docs/api/java/lang/ProcessBuilder.html

    替代方案包括;将错误写入文件,或在另一个线程中读取。

    【讨论】:

    • 非常感谢彼得,这有帮助,但我仍然在 read() 上被阻止。请查看我的更新。
    • @gamlieldor 我建议您在运行时打印输出。很可能是我们在等待输入。
    • 我做了,你是对的,它正在等待第二个问题的输入。如何让第一个问题和第二个问题的答案分别为“y”?我尝试将 pb 输入重定向到一个由新行分隔的 'y' 文件,但没有帮助。
    • @gamlieldor 我会检查程序如何读取输入。一个常见的错误是为每一行输入使用一个新的扫描器,这可能会导致一些输入被转储。
    猜你喜欢
    • 2013-10-23
    • 2018-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-03
    • 2013-08-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多