java - 在 Java 中将输入流重用到进程

标签 java stream ioexception processbuilder bufferedwriter

我正在使用 ProcessBuilder 从 C++ 程序输入和接收信息,使用 Java。启动该过程一次后,我希望能够输入新字符串并接收其输出,而不必重新启动整个过程。这是我迄今为止采取的方法:

public void getData(String sentence) throws InterruptedException, IOException{
        InputStream stdout = process.getInputStream();
        InputStreamReader isr = new InputStreamReader(stdout);
        OutputStream stdin = process.getOutputStream();
        OutputStreamWriter osr = new OutputStreamWriter(stdin);
        BufferedWriter writer = new BufferedWriter(osr);
        BufferedReader reader = new BufferedReader(isr);

        writer.write(sentence);
        writer.close();

        String ch = reader.readLine();
        preprocessed="";
        while (ch!=null){
            preprocessed = preprocessed+"~"+ch;
            ch = reader.readLine();
        }

        reader.close();
}

每次我想向正在运行的进程发送输入时,我都会调用此方法。然而,有一个问题:我第一次发送输入时,一切都很好,并且输出也被完美接收。但是,第二次调用它时,我收到错误

java.io.IOException: Stream closed

这是出乎意料的,因为理论上,当再次调用该方法时,所有内容都会重新创建。此外,删除关闭 BufferedWriter 的行会导致代码在下一行暂停,就好像 BufferedReader 正在等待 BufferedWriter 关闭一样。

最后一件事 - 即使我创建一个新的 BufferedWriter 并指示该方法在第二次调用时使用该方法,我也会得到相同的异常,我根本不理解。

有什么办法可以解决这个问题吗?

非常感谢!

最佳答案

发生意外的 IOException 是因为当 Readers 和 Writers 关闭时,它们会依次关闭其底层流。

当您第一次调用您的方法时,一切似乎都正常。但是您关闭编写器,这会关闭进程输出流,从而从进程的角度关闭标准输入。不确定你的 C++ 二进制文件是什么样子,但可能在完成所有输入后它会愉快地退出。

因此对您的方法的后续调用不起作用。

Reader 端存在一个单独但类似的问题。您调用 readLine() 直到它返回 null,这意味着 Reader 已感觉到流的结尾。但这仅当进程完全完成其标准输出时才会发生。

您需要某种方法来识别何时处理完一个工作单元(无论您所说的“句子”是什么意思),而无需等待整个流结束。流没有输出之间逻辑暂停的概念。这只是一个连续的流。 Reader 和 Writer 只是字节和字符之间缓冲的薄层,但基本上与流相同。

也许输出可以有分隔符。或者,您可以在实际发送输出之前发送每个输出 block 的长度,并以这种方式区分输出。或者也许您事先知道每个回复需要多长时间?

您只能通过直播获得一次机会。所以他们必须比这种方法更长久。如果您想避免每次都重新启动进程,则无法打开和关闭流。 (进程还有其他方式进行通信,例如套接字,但这可能超出了范围。)

从正交的角度来看,当您累积输出时,附加到 StringBuilder 通常比字符串连接的大循环更有效。

您可能还需要进行一些线程检查 process.exitValue() 或以其他方式确保进程按预期工作。

关于java - 在 Java 中将输入流重用到进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33459145/

相关文章:

java - 数据库中的数据如何在不同的 Activity 中分配给数组?

.net - .NET Streams 是否节省内存?

c++ - 为什么 istringstream 在流的末尾附加 '-1' 字符?

java - 为什么 Java FileChannel.truncate 仅在 Windows 上可预见地失败?

java - 如何使用 Java 运行时打印 Python 脚本的 std 输出?

java - AdoptOpenJDK8 找不到 Openjfx 包,即使它是依赖项

java - Vaadin 8 历史 API 和 SEO

java - Spring 无法注入(inject)实体管理器工厂

c# - HttpWebRequest 分块/异步 POST

c# - File.Open 不会在 File.Move 时抛出 IOException