Java进程:单线程读取子进程的stdout和stderr
Java Process: read stdout and stderr of a subprocess in a single thread
假设我在 Java 中启动了一个子进程,它可能会写入 stdout 和 stderr:
Process subprocess = Runtime.getRuntime().exec(…);
我想阅读它所有的标准输出和标准错误;或者干脆忽略它们。
如果我这样做:
readAllFrom(subprocess.getInputStream()); //stdout is getInputStream, weird!
readAllFrom(subprocess.getErrorStream()); //stderr
…如果子进程首先尝试将数据输出到 stderr 并因此在该点阻塞,它会卡住。
如果我这样做:
while (…) {
readLineFrom(subprocess.getInputStream());
readLineFrom(subprocess.getErrorStream());
}
……其实风险好像是一样的
如果我这样做:
while (…) {
nonblockingReadFrom(subprocess.getInputStream());
nonblockingReadFrom(subprocess.getOutputStream());
}
其中 nonblockingReadFrom
可以是这样的:
… nonblockingReadFrom(InputStream stream) {
byte[] buffer = new byte[…];
stream.read(buffer, 0, Math.min(stream.available(), buffer.length));
…
}
…如果子进程输出数据有一些暂停,它将产生无用的 100%-CPU-负载。
当然,我可以创建单独的线程。像这里这样的东西(需要1, 2). But my question is about doing all in the same thread. Probably, something like Java interface to select system call。
所以,问题是:是否可以在不使用额外线程或临时文件的情况下正确处理 Java 中 java.lang.Process
类型的子进程的标准输出和标准错误?
不,您不能只从 Process
返回的 InputStream
创建 SelectableChannel
,这是 Java api 的限制 AFAICT .
假设我在 Java 中启动了一个子进程,它可能会写入 stdout 和 stderr:
Process subprocess = Runtime.getRuntime().exec(…);
我想阅读它所有的标准输出和标准错误;或者干脆忽略它们。
如果我这样做:
readAllFrom(subprocess.getInputStream()); //stdout is getInputStream, weird! readAllFrom(subprocess.getErrorStream()); //stderr
…如果子进程首先尝试将数据输出到 stderr 并因此在该点阻塞,它会卡住。
如果我这样做:
while (…) { readLineFrom(subprocess.getInputStream()); readLineFrom(subprocess.getErrorStream()); }
……其实风险好像是一样的
如果我这样做:
while (…) { nonblockingReadFrom(subprocess.getInputStream()); nonblockingReadFrom(subprocess.getOutputStream()); }
其中
nonblockingReadFrom
可以是这样的:… nonblockingReadFrom(InputStream stream) { byte[] buffer = new byte[…]; stream.read(buffer, 0, Math.min(stream.available(), buffer.length)); … }
…如果子进程输出数据有一些暂停,它将产生无用的 100%-CPU-负载。
当然,我可以创建单独的线程。像这里这样的东西(需要1, 2). But my question is about doing all in the same thread. Probably, something like Java interface to select system call。
所以,问题是:是否可以在不使用额外线程或临时文件的情况下正确处理 Java 中 java.lang.Process
类型的子进程的标准输出和标准错误?
不,您不能只从 Process
返回的 InputStream
创建 SelectableChannel
,这是 Java api 的限制 AFAICT .