首先让我向SO社区道歉,告诉你一些应该是如此微不足道的东西。但是我整天都在这里,而且我已经走到了尽头。
我的程序中有一部分需要从输入流中提取文本,并从使用Runtime.getrunTime()。exec()启动的进程中获取错误流,并将其有序地传递给标准输入和输出方式。我有一个功能,因为我可以告诉应该工作。但它似乎陷入了陷阱 - 它正在等待流报告准备好 - 但流已经完成并且没有报告。我很困惑。我想不出另一种方法可以做到这符合我的约束,而我更加怀疑这样的捕获22可以存在。
这是我的代码:
private void forwardStreamtoStd(InputStream in, InputStream err)
throws IOException {
int c = -1;
BufferedReader inReader = new BufferedReader(
new InputStreamReader(in, "US-ASCII"));
BufferedReader errReader = new BufferedReader(
new InputStreamReader(err, "US-ASCII"));
boolean inFinished = false, errFinished = false;
try {
System.out.println("Begin stream read loop...");
while (!inFinished && !errFinished) {
if (!inFinished) {
while (inReader.ready()) {
if ((c = inReader.read()) == -1) {
inFinished = true;
}
else {
System.out.print((char) c);
}
}
}
if (!errFinished) {
while (errReader.ready()) {
if ((c = errReader.read()) == -1) {
errFinished = true;
}
else {
System.err.print((char) c);
}
}
}
}
System.out.println("End stream read loop.");
}
catch (IOException e) {
throw e;
}
finally {
errReader.close();
inReader.close();
}
}
问题似乎是读取循环正在等待流报告准备好,结果是没有看到读取返回的-1告诉他们是时候退出了。我试图避免流阻塞,这样我就可以在他们准备好时依次从两者中取出。但是,如何才能捕获进程的流结束?我错过了什么吗?不应该读报告它在流-1结束时被读取?这些过程正在完成,所以他们的流应该死了。我在这里做错了什么?
答案 0 :(得分:8)
还有两种可能性:
redirectErrorStream(true)
加入两个流,您需要读取一个流。我有一个例子here。inheritIO()
自动转发所有内容编辑在第二个猜测中,似乎ready()调用误导了您的程序。试试这个:
private void forwardStreamtoStd(InputStream in, InputStream err)
throws IOException {
int c = -1;
BufferedReader inReader = new BufferedReader(
new InputStreamReader(in, "US-ASCII"));
BufferedReader errReader = new BufferedReader(
new InputStreamReader(err, "US-ASCII"));
boolean inFinished = false, errFinished = false;
try {
System.out.println("Begin stream read loop...");
if (!inFinished) {
while ((c = inReader.read()) != -1) {
System.out.print((char) c);
}
inFinished = true;
}
if (!errFinished) {
while ((c = errReader.read()) != -1) {
System.err.print((char) c);
}
errFinished = true;
}
System.out.println("End stream read loop.");
}
catch (IOException e) {
throw e;
}
finally {
errReader.close();
inReader.close();
}
}
或者更好的是,如果你没有计划任何额外的转换,请不要使用BufferedReader:
private void createReader(final InputStream in, final OutputStream out) {
new Thread() {
public void run() {
try {
int c = 0;
while ((c = in.read()) != -1) {
out.write(c);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
in.close();
}
}
}.start();
}
private void forwardStreamtoStd(InputStream in, InputStream err)
throws IOException {
createReader(in, System.out);
createReader(err, System.err);
}
答案 1 :(得分:5)
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4090471
我一直使用的解决方案是创建一个单独的线程来读取其中一个流,在主线程完成读取时加入线程,然后等待该过程。
答案 2 :(得分:3)
必需同时使用2个流,以防止阻塞。有关详细信息,请参阅this article,特别注意在单独的线程中捕获stdout / err的StreamGobbler
机制。
答案 3 :(得分:1)
如果我没记错的话,生成的进程永远不会关闭流 - 所以你需要让读者进入自己的线程,在主线程上休眠直到进程完成,然后关闭阅读器。