gpt4 book ai didi

Java exec方法,如何正确处理流

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:28:00 25 4
gpt4 key购买 nike

从 Java 生成和使用外部进程流 (IO) 的正确方法是什么?据我所知,由于缓冲区大小可能有限,Java 端输入流(进程输出)应该在与生成进程输入并行的线程中使用。

但我不确定我是否最终需要与那些消费者线程同步,或者仅仅使用 waitFor 方法等待进程退出是否足够,以确保所有进程输出真的被消耗了吗? I.E 是否有可能,即使进程退出(关闭它的输出流),流的 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>相反,将行放在那里而不进行任何转换,最后在循环中检索它们。

关于Java exec方法,如何正确处理流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42759653/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com