简体   繁体   English

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

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

I have a snippet as follows: 我有一个片段如下:

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

Now in the above code I am sure that process will always have on line input, so I did not use any kind of while loop or any null check. 现在在上面的代码中我确信该进程将始终具有在线输入,因此我没有使用任何类型的while循环或任何null检查。 The problem is readLine blocks. 问题是readLine块。 The one reason I was aware of is, the stream having no data to read and hence readLine keeps waiting. 我知道的一个原因是,流没有数据要读取,因此readLine一直在等待。 To check this, I removed readLine and used read() function as follows: 为了检查这一点,我删除了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);
}

To my surprise this code worked and printed the messags New line and Carriage return. 令我惊讶的是,这段代码工作并打印出麻烦的新行和回车。 Now I am wondering why did the readLine block? 现在我想知道为什么readLine块? The data is available it is terminated by newline. 数据可用,它由换行符终止。 What else could be the reason?? 还有什么可能的原因?

Note: The above worked once in a while! 注意:以上工作偶尔一次! Maybe once out of 15times. 也许一次超过15次。
Note: I tried using ProcessBuilder too, but same behaviour. 注意:我也尝试使用ProcessBuilder,但行为相同。

UPDATE: So I switched to ProcessBuilder and then I redirected the errorStream and now I get both input stream and error stream at once when I do process.getInputStream and this works fine. 更新:所以我切换到ProcessBuilder,然后我重定向了errorStream,现在当我执行process.getInputStream时,我立即得到输入流和错误流,这很好。 Below is the snippet. 以下是片段。

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.

I would like to differentiate my error stream from input stream but with this method they are all jumbled up! 我想区分我的错误流和输入流,但是使用这种方法它们都混乱了! Any ideas on this? 有什么想法吗?

You can use threads, in order to avoid it. 您可以使用线程,以避免它。

Like One slave thread which will be responsible for reading. 像一个负责阅读的奴隶线程。 This will not halt your progress of program. 这不会阻止您的计划进度。

I think the problem is not that the standard error is blocking, but that the standard output is blocking causing the application you are calling to block. 我认为问题不在于标准错误是阻塞,而是标准输出阻塞导致您调用的应用程序阻塞。

Standard output is normally buffered. 标准输出通常是缓冲的。 If the process you are calling writes less to standard output than the buffer size all is well and it can reach the code that writes to standard error. 如果您调用的进程写入的标准输出少于缓冲区大小,那么一切都很好,它可以达到写入标准错误的代码。 If the process fills the buffer, its attempt to write to standard output will block and it will never reach the point where it writes to standard error. 如果进程填充缓冲区,则其写入标准输出的尝试将被阻止,并且它将永远不会到达写入标准错误的位置。

This could be why you see it working occasionally - sometimes the standard output does not fill the buffer. 这可能是您偶尔看到它工作的原因 - 有时标准输出不会填充缓冲区。 It could also be why it works after a long time: eventually the write to standard output times out. 这也可能是它在很长一段时间后工作的原因:最终写入标准输出超时。

As a demonstration, this simple process always block like you describe on my Windows 8 machine: 作为演示,这个简单的过程总是像你在我的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");
    }
}

So to avoid getting the error stream and input stream merged just remove the line pb.redirectErrorStream(true); 因此,为避免获取错误流和输入流合并,只需删除行pb.redirectErrorStream(true);

Because as said in the java doc : 因为正如java doc中所述:

if this property is true, then any error output generated by subprocesses subsequently started by this object's start() method will be merged with the standard output, so that both can be read using the Process.getInputStream() method. 如果此属性为true,则此对象的start()方法随后启动的子进程生成的任何错误输出将与标准输出合并,以便可以使用Process.getInputStream()方法读取这两者。 This makes it easier to correlate error messages with the corresponding output. 这使得更容易将错误消息与相应的输出相关联。 The initial value is false. 初始值为false。

By calling pb.redirectErrorStream(true); 通过调用pb.redirectErrorStream(true); you are merging both output. 你正在合并两个输出。

getErrorStream states the following Returns the input stream connected to the error output of the subprocess. getErrorStream声明以下内容返回连接到子进程的错误输出的输入流。 The stream obtains data piped from the error output of the process represented by this Process object. 该流获取从此Process对象表示的进程的错误输出中传输的数据。 If the standard error of the subprocess has been redirected using ProcessBuilder.redirectError or ProcessBuilder.redirectErrorStream then this method will return a null input stream. 如果使用ProcessBuilder.redirectError或ProcessBuilder.redirectErrorStream重定向子进程的标准错误,则此方法将返回空输入流。

and the ReadLine states the following Reads a line of text. 并且ReadLine声明以下内容读取一行文本。 A line is considered to be terminated by any one of a line feed ('\\n'), a carriage return ('\\r'), or a carriage return followed immediately by a linefeed. 一条线被认为是由换行符('\\ n'),回车符('\\ r')或回车符中的任何一个终止,后面紧跟换行符。

Based on the explanation provided to the API. 基于提供给API的解释。 readline waits indefinitely to get line feed or carriage return where as processbuilder returns NULL that is why readLine terminates for the same. readline无限期地等待获取换行或回车,因为processbuilder返回NULL,这就是readLine为此终止的原因。

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

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