繁体   English   中英

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

[英]BufferedReader.readLine blocks my program but BufferedReader.read() reads properly

我有一个片段如下:

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.

我想区分我的错误流和输入流,但是使用这种方法它们都混乱了! 有什么想法吗?

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

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

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

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

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

作为演示,这个简单的过程总是像你在我的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");
    }
}

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

因为正如java doc中所述:

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM