BufferedReader.readLine阻止我的程序,但BufferedReader.read()正确读取

时间:2014-12-16 14:34:54

标签: java bufferedreader

我有一个片段如下:

Process proc = Runtime.getRuntime().exec(command);
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String line = br.readLine();

现在在上面的代码中我确信该进程将始终具有在线输入,因此我没有使用任何类型的while循环或任何null检查。问题是readLine块。我知道的一个原因是,流没有数据要读取,因此readLine一直在等待。为了检查这一点,我删除了readLine并使用了read()函数,如下所示:

Process proc = Runtime.getRuntime().exec( command );
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
int a;
while((a=br.read())!=-1){
    char ch = (char) a;
    if(ch == '\n')
        System.out.print("New line "+ch);
    if(ch == '\r')
        System.out.print("Carriage return "+ch);
    System.out.print(ch);
}

令我惊讶的是,这段代码工作并打印出麻烦的新行和回车。现在我想知道为什么readLine块?数据可用,它由换行符终止。还有什么可能的原因?

注意:以上工作偶尔一次!也许一次出15次 注意:我也尝试使用ProcessBuilder,但行为相同。

更新: 所以我切换到ProcessBuilder然后我重定向了errorStream,现在当我执行process.getInputStream时,我立刻得到输入流和错误流,这很好。以下是摘录。

ProcessBuilder pb = new ProcessBuilder(command.split(" "));
pb..redirectErrorStream(true);
Process proc = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = br.readLine();
//Now I get both input and error stream.

我想区分我的错误流和输入流,但是使用这种方法它们都混乱了!关于这个的任何想法?

4 个答案:

答案 0 :(得分:2)

您可以使用线程,以避免它。

像一个负责阅读的奴隶线程。这不会阻止你的课程进度。

答案 1 :(得分:1)

我认为问题不在于标准错误是阻塞,而是标准输出阻塞导致您调用的应用程序阻塞。

标准输出通常是缓冲的。如果您调用的进程写入的标准输出少于缓冲区大小,那么一切都很好,它可以达到写入标准错误的代码。如果进程填充缓冲区,则其写入标准输出的尝试将被阻止,并且它将永远不会到达写入标准错误的位置。

这可能是您偶尔看到它工作的原因 - 有时标准输出不会填充缓冲区。这也可能是它长时间工作的原因:最终写入标准输出超时。

作为演示,这个简单的过程总是像你在我的Windows 8机器上描述的那样阻塞:

public class Proc {

    public static void main(String[] args) {
        for(int i=0;i<1000;i++) {
            System.out.print("More data ");
        }
        System.out.println();
        System.err.println("An error line");
    }
}

答案 2 :(得分:0)

因此,为了避免错误流和输入流合并,只需删除该行 pb.redirectErrorStream(true);

因为如java doc所述:

  

如果此属性为true,则此对象的start()方法随后启动的子进程生成的任何错误输出将与标准输出合并,以便可以使用Process.getInputStream()读取这两个错误输出方法。这使得更容易将错误消息与相应的输出相关联。初始值为false。

通过调用pb.redirectErrorStream(true);,您正在合并两个输出。

答案 3 :(得分:0)

getErrorStream声明如下 返回连接到子进程的错误输出的输入流。该流获取从此Process对象表示的进程的错误输出中传输的数据。 如果使用ProcessBuilder.redirectError或ProcessBuilder.redirectErrorStream重定向子进程的标准错误,则此方法将返回空输入流。

并且ReadLine声明如下 读一行文字。一条线被认为是由换行符('\ n'),回车符('\ r')或回车符中的任何一个终止,后面紧跟换行符。

基于提供给API的解释。 readline无限期地等待获取换行符或回车符,因为processbuilder返回NULL,这就是readLine终止为止的原因。