流程启动后,ProcessBuilder停止提供数据。

问题描述 投票:0回答:1

我需要从运行在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时停顿。

  • 我试过使用重定向来发送stdout到一个文件中。
  • 我试着只读stderr
  • 我试着在另一条线上阅读 waitFor 在主
  • 我试着在另一条线上阅读,但没有 mainFor 在主
  • 我试着不读 Thread.sleep 而不是等待
  • 我试过了 "/bin/bash", "-c", exec+" "+execFile 流程建设者
  • 我试着用Runtime.exe代替ProcessBuilder。
  • 我试过了 "/bin/bash", "-c", "while :; do echo 1; done". 这居然突破了38万字节的限制,和预想的一样,无限的走了。

这是怎么回事,我该如何解决?

P.S. unix可执行文件的源代码是 此处但我不认为它很有用,因为它是在CMD上工作的。

java process windows-subsystem-for-linux processbuilder
1个回答
0
投票

我在打字的时候找到了答案。显然,你必须以某种方式同时处理STDERR和STDOUT流,它们不会就这样消失。如果你只读取其中一个而忽略另一个,最终被忽略的那个流的缓冲区会变得太大而阻塞,直到它被清空。

所以加入以下代码解决了这个问题

new Thread( () -> {
     try (InputStream es = csvBuilder.getErrorStream() ){
            IOUtils.skip(es, Long.MAX_VALUE);
     } catch (IOException e) {
            throw new RuntimeException(e);
     }
}).start();
© www.soinside.com 2019 - 2024. All rights reserved.