从 Java 生成和使用外部进程的流(IO)的正确方法是什么?据我所知,由于缓冲区大小可能有限,java最终输入流(进程输出)应该在线程中并行消耗以生成进程输入。
但我不确定我最终是否需要与这些消费者线程同步,或者只是等待进程退出就足够了waitFor
方法,以确定所有过程输出实际上都被消耗了?即是否有可能,即使进程退出(关闭其输出流),流的 java 端仍然有未读的数据?如何waitFor
实际上甚至知道该过程何时完成?对于所讨论的过程,EOF(关闭其输入流的java端)指示其退出。
我当前处理流的解决方案如下
public class Application {
private static final StringBuffer output = new StringBuffer();
private static final StringBuffer errOutput = new StringBuffer();
private static final CountDownLatch latch = new CountDownLatch(2);
public static void main(String[] args) throws IOException, InterruptedException {
Process exec = Runtime.getRuntime().exec("/bin/cat");
OutputStream procIn = exec.getOutputStream();
InputStream procOut = exec.getInputStream();
InputStream procErrOut = exec.getErrorStream();
new Thread(new StreamConsumer(procOut, output)).start();
new Thread(new StreamConsumer(procErrOut, errOutput)).start();
PrintWriter printWriter = new PrintWriter(procIn);
printWriter.print("hello world");
printWriter.flush();
printWriter.close();
int ret = exec.waitFor();
latch.await();
System.out.println(output.toString());
System.out.println(errOutput.toString());
}
public static class StreamConsumer implements Runnable {
private InputStream input;
private StringBuffer output;
public StreamConsumer(InputStream input, StringBuffer output) {
this.input = input;
this.output = output;
}
@Override
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line;
try {
while ((line = reader.readLine()) != null) {
output.append(line + System.lineSeparator());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
latch.countDown();
}
}
}
}
}
这里是否有必要使用闩锁,或者waitFor
暗示所有输出都已被消耗?另外,如果输出没有结束/不包含新行,readLine
错过了输出,或者仍然阅读剩下的所有内容?读取 null 是否意味着进程已关闭其流的末尾 - 是否还有其他可以读取 null 的情况?
处理流的正确方法是什么,我可以做得比我的示例更好吗?
waitFor
表示进程已结束,但您无法确定从其 stdout 和 stderr 收集字符串的线程也已完成,因此使用锁存器是朝着正确方向迈出的一步,但不是最佳方向。
您可以直接等待线程,而不是等待闩锁:
Thread stdoutThread = new Thread(new StreamConsumer(procOut, output)).start();
Thread stderrThread = ...
...
int ret = exec.waitFor();
stdoutThread.join();
stderrThread.join();
顺便说一句,将行存储在StringBuffer
s 是无用的工作。使用ArrayList<String>
相反,将行放在那里而不进行任何转换,最后在循环中检索它们。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)