【问题标题】:In Java, BufferedReader readLine blocks on interactive shell在 Java 中,BufferedReader readLine 在交互式 shell 上阻塞
【发布时间】:2017-07-09 10:45:48
【问题描述】:

我有一个 jar 文件,它一直在等待用户输入、处理和打印结果(多行),就像这样

>Input sentence 1
Result 1
Result 2
>Input sentence 2
Result 1
Result 2
Result 3
>

退出这个jar程序的唯一方法是按Ctrl + C。

现在,我想从我的 java 程序中调用这个 jar 文件。我的代码如下所示:

processBuilder = new ProcessBuilder(PATH_TO_BIN);
Process process = processBuilder.start();
writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

writer.write(inputSentence);
writer.newLine();
writer.flush();
String line;
while ((line = reader.readLine()) != null){ //<<<< it hangs here
    System.out.println(line);
}

我的程序可以成功打印出“jar”程序返回的结果,但是一直挂在下一个reader.readLine(),我无法为“jar”程序提供下一个输入。

有没有办法解决这个问题?

提前致谢!

【问题讨论】:

  • 您没有在 while 循环中向 jar 中写入任何内容。它等待输入,而您正在等待它的输出。在 `System.out.println 之后添加一些 write
  • @AhmadWabbi 也许我在我的问题中没有说得很清楚,但是 JAR 文件可能会产生多行结果,而不仅仅是一行,这就是为什么我需要使用 @ 读取所有结果行987654326@循环如你所见
  • 在您的示例中甚至不清楚。在这种情况下,无法区分您的程序等待下一个结果和永远等待,因为 jar 完成了生成结果并等待 Ctrl-C。即使 peek 也无法区分。除了在足够的超时后使用线程发送 Ctrl-C 之外,我没有看到其他解决方案。

标签: java


【解决方案1】:

您可以使用一个线程读取和另一个写入,然后它不会在读取时阻塞,如下所示:

    ProcessBuilder processBuilder = new ProcessBuilder(PATH_TO_BIN);
    Process process = processBuilder.start();
    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));

      
    new Thread () {
      public void run() {
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line = null;
        do {             
          line = reader.readLine();
          System.out.println(line);
        } while (line != null); // <<<< it waits here for next line of input 
      }
    }.start();
       

    // and here you can write something to the process InputSteram...
    writer.write(inputSentence);
    writer.newLine();
    writer.flush();

【讨论】:

  • 我很抱歉没有足够清楚地指定,结果可能有多行,而不仅仅是我最初示例中的单行。我更新了我的问题。
  • 它不会“在此处等待下一行输入”,其中“此处”是 do/while 条件。它在readLine() 等待。
【解决方案2】:

来自 BufferedReader 的方法 ready() - 判断该流是否准备好被读取。

您可以使用此方法检查流是否已准备好被读取,如果是,您可以完成您的工作,

while (reader.ready()){
//Do the processing
}

看看这是否有效。

【讨论】:

  • 我确实尝试过使用这个ready 方法,但是它返回了false 并且没有进入while 循环的主体。
  • 这不会阻止readLine()在行终止符未发送的情况下阻塞。
【解决方案3】:

我将以 @Krzystof 的回答为基础,但我假设您将使用 Java 7 或 8 (+)。

在这种情况下,您应该使用 Try-With-Resources,如下所示:

public static void main (String[] args) throws java.lang.Exception {

    ProcessBuilder prBuilder = new ProcessBuilder("/path/to/bin");
    Process process = prBuilder.start();
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())) | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()))) {

        String line;

        while ((line = reader.readLine()) != null) {
            // Process input
        }

    } catch (IOException ex) {
        // Process IOException
    } finally {
        process.kill();
    }
}

【讨论】:

  • 感谢分享。但是,这段代码仍然挂在line = reader.readLine(),对吧?我还更新了我的问题以获取更多详细信息
  • 您可以使用以下条件:while (reader.peek() != -1) 我确定确切的行为,但我不知道它“挂起”。但无论如何,应用程序等待下一个输入是好的。否则,您将传递可能不完整的数据。你有什么理由需要持续输入/输出?
  • 我在 BufferedReader 对象上没有看到peek() 方法,可能是Java 6。我使用的是Java 8。JAR 文件由第三方提供,我无法控制超过它。我想要的是要求用户提供输入,将其传递给 JAR 程序并获取输出。 JAR 文件每次启动时都需要初始化一堆模型。
  • 即使使用peek(),在读取结果的最后一行后仍然挂起。似乎我的程序不知道它是否已完成从 JAR 文件中读取所有输出并一直等待
猜你喜欢
  • 2018-09-26
  • 2013-08-10
  • 2019-10-30
  • 1970-01-01
  • 2011-12-12
  • 2020-12-05
  • 2013-10-23
  • 1970-01-01
  • 2016-05-29
相关资源
最近更新 更多