2011-03-09 61 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