2011-03-09 94 views
10

我有这样的代码使用BufferedReader读取文本文件:BufferedReader.ready()方法确保readLine()方法不返回NULL吗?

BufferedReader reader=null; 
    try { 
     reader = new BufferedReader(new FileReader("file1.txt")); 

     while (reader.ready()) { 
      final String line = reader.readLine(); 
      System.out.println("<"+line+">"); 
     } catch (..) 
    { 
     ... 
    } 

它工作正常,但FindBugs的报告警告:

NP_DEREFERENCE_OF_READLINE_VALUE:调用的readLine(的 结果)是 解除引用不如果结果为空,则检查 。如果没有 多行文本要读取,则readLine()将返回空值并取消引用 ,这将生成空指针 异常。

当我改变FileReaderStringReader,即

BufferedReader reader=null; 
    try { 
     reader = new BufferedReader(new StringReader("ABCD")); 

     while (reader.ready()) { 
      final String line = reader.readLine(); 
      System.out.println("<"+line+">"); 
     } catch (..) 
    { 
     ... 
    } 

readLine方法返回nullready方法始终返回true - 实际上这是一个无限循环。

这似乎readLine可能返回null即使ready回报true。但为什么不同Reader s的行为有所不同?

UPDATE:

我知道正常的方式来阅读文本文件(就像彼得和阿里所示)。但是我从同事那里读了那段代码,并意识到我不知道ready方法。然后我读了JavaDoc,但不明白block。然后我做了一个测试并发布了这个问题。所以,提出这个问题的更好的方法可能是:

什么时候输入被阻塞?如何使用ready方法(或为什么不使用它)?为什么那些2 ReaderFileReaderStringReader)的行为与ready方法不同?

回答

13

的准备方法告诉我们,如果流已准备好被读取。

想象一下,您的数据流正在从网络套接字读取数据。在这种情况下,流可能没有结束,因为套接字尚未关闭,但它可能尚未准备好接收下一个数据块,因为套接字的另一端未推送更多数据。

在上面的场景中,我们无法读取任何更多的数据,直到远端推送它,所以我们必须等待数据变为可用,或者要关闭套接字。 ready()方法告诉我们数据何时可用。

6

这里是的Javadoc不得不说:

判断此流是否已准备好被读取。如果缓冲区不是空的,或者底层字符流已准备就绪,缓冲字符流就绪。

所以一个BufferedReader被认为是准备简单,如果底层流也准备好了。由于BufferedReader是一个包装器,这个基础流可以是任何Reader实现;因此ready()的语义是在接口上声明的:

如果下一个read()保证不会阻塞输入,则返回true,否则返回false。请注意,返回false并不能保证下一次读取会被阻塞。

所以你才真正得到时机保证,即该read()不会阻止。调用ready()的结果告诉你绝对没有任何关于内容你会从read()调用回来,所以不能用于删除空检查。

+6

不幸的是readLine(),ready()只保证有一个字符可用,即read()不会被阻塞。如果存在数据但不是完整的行,readLine()将会阻塞。代码 – 2011-03-09 11:15:32

11

Reader.ready()和InputStream.available()很少按照您的喜好工作,我不建议您使用它们。要阅读你应该使用的文件

String line; 
while ((line = reader.readLine()) != null) 
    System.out.println("<"+line+">"); 
+3

代码在reader.readline()行上永久挂起。有什么建议么? – Paul 2012-03-30 18:25:37

+1

这意味着另一端是不发送一个新行(可能是其他任何东西) – 2012-03-30 21:31:37

+0

不,不是它;我在openssl中在命令行上做得很好 – Paul 2012-03-30 21:43:31

1

看看the API for ready

你在做什么是错误的。 ready()只会告诉您流是否可读且有效。阅读该链接返回的评论。

你想要做的是:

String thisLine; 

//Loop across the arguments 
for (int i=0; i < args.length; i++) { 

    //Open the file for reading 
    try { 
    BufferedReader br = new BufferedReader(new FileReader(args[i])); 
    while ((thisLine = br.readLine()) != null) { // while loop begins here 
     System.out.println(thisLine); 
    } // end while 
    } // end try 
    catch (IOException e) { 
    System.err.println("Error: " + e); 
    } 
} // end for