我需要从在Windows上运行的java运行一个unix程序。 unix 程序将文件名作为第一个参数,处理该文件,并在 stdout 上返回处理后的文件。
以下内容在 CMD 控制台上完美运行:
wsl.exe /home/user/process /mnt/c/Users/user/input
它将 stdout 和 stderr 打印到控制台;或者我可以将 stdout 重定向到一个新文件,该文件大小为 1.2MB。
我想用 Java 做同样的事情。下面的代码是最简化的版本
ProcessBuilder toCsv = new ProcessBuilder("wsl.exe", "/home/user/process", "/mnt/c/Users/user/input");
Process proc = toCsv.start();
try (InputStream is = proc.getInputStream()){
for(int i=0; is.read() != -1; i++) {
System.out.println(i);
}
}
这总是在字节号 380927 处停止。调试器显示它在 FileInputStream.read 上停止
- 我尝试使用重定向将标准输出发送到文件
- 我尝试只读取 stderr
- 我尝试在主线程上使用
waitFor
在不同的线程上读取 - 我尝试在主线程上没有
mainFor
的情况下在不同的线程上读取 - 我尝试在不使用
Thread.sleep
而不是 waitFor 的情况下进行阅读 - 我尝试将
"/bin/bash", "-c", exec+""+execFile
传递给 ProcessBuilder - 我尝试使用 Runtime.exec 而不是 ProcessBuilder
- 我尝试了
“/bin/bash”、“-c”、“while :; do echo 1; done”
。这实际上突破了 380k 字节的限制,并且像预期的那样无限延伸。
发生了什么事,如何解决?
附注unix 可执行文件的源是 here ,但我认为它不是很有用,因为它可以从 CMD 运行
最佳答案
我在打字时找到了答案。显然,您必须以某种方式处理 STDERR 和 STDOUT 流,它们不会消失。如果您只读取其中一个而忽略另一个,最终被忽略的缓冲区将变得太大并阻塞,直到它被清空。
所以添加以下代码解决了它
new Thread( () -> {
try (InputStream es = csvBuilder.getErrorStream() ){
IOUtils.skip(es, Long.MAX_VALUE);
} catch (IOException e) {
throw new RuntimeException(e);
}
}).start();
关于java - ProcessBuilder 启动的进程停止提供数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61441484/