我需要从运行在windows上的java中运行一个unix程序,这个unix程序以文件名为第一个参数,处理文件,并在stdout上返回处理后的文件。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时停顿。
waitFor
在主mainFor
在主Thread.sleep
而不是等待"/bin/bash", "-c", exec+" "+execFile
流程建设者"/bin/bash", "-c", "while :; do echo 1; done"
. 这居然突破了38万字节的限制,和预想的一样,无限的走了。这是怎么回事,我该如何解决?
P.S. unix可执行文件的源代码是 此处但我不认为它很有用,因为它是在CMD上工作的。
我在打字的时候找到了答案。显然,你必须以某种方式同时处理STDERR和STDOUT流,它们不会就这样消失。如果你只读取其中一个而忽略另一个,最终被忽略的那个流的缓冲区会变得太大而阻塞,直到它被清空。
所以加入以下代码解决了这个问题
new Thread( () -> {
try (InputStream es = csvBuilder.getErrorStream() ){
IOUtils.skip(es, Long.MAX_VALUE);
} catch (IOException e) {
throw new RuntimeException(e);
}
}).start();