4

很抱歉,如果我失去了一些東西在這裏很明顯......但請看看這個代碼片段:Java BufferedReader.readLine()不等待EOL?

String readString; 
String writeString = "O hai world."; 
BufferedReader br = new BufferedReader(
    new InputStreamReader( 
     new ByteArrayInputStream(writeString.getBytes()), 
     "UTF-8"), 
    1024); 
readString = br.readLine(); 
System.out.println("readString: " + readString); 

我預計這將打印「readString:空」,因爲我認爲BufferedReader中會遇到一個EOF在檢測到有效的EOL之前,而是打印出「readString:O hai world」。這看起來與Javadocs for BufferedReader所說的readLine()將做的相反:

讀取一行文本。換行符被換行符('\ n'),回車符('\ r')或回車符後面的換行符中的任何一個結束。

返回: 包含該行的內容,不包括任何行終止符,則返回null流的末尾已到達

我看不出有任何理由的字符串我字符串將被重新解釋爲以'\ n'和/或'\ r'結尾......有人可以照亮我嗎?謝謝!

編輯: 提供一些背景,我試着寫JUnit測試來驗證我寫它的設計上System.in讀閱讀器類。使用ByteArrayInputStreams似乎是模擬System.in的合理方法(請參閱this relevant SO post)。

當我的Reader捕獲一條線時,它當前依賴於BufferedReader.readLine()。出於我的目的,我的讀者必須全部以'\ n'或'\ r'結尾。遇到沒有EOL的EOF不應解析爲有效行。所以我想我現在的問題如下(我會盡量在我有空的時候更詳細地測試這些,但希望你們聰明的人能夠幫助我):

  • BufferedReader.readLine()損壞/錯誤記錄?或者ByteArrayInputStream在其字節數組耗盡時返回錯誤的東西?
  • 這是測試我的Reader錯誤的方法,我應該期待readLine()在針對System.in使用時能夠正常工作嗎?我傾向於相信答案是肯定的。
  • 有沒有更好的方法來模擬System.in進行單元測試?
  • 如果我在從InputStream中讀取時需要嚴格區分'\ n'和'\ r',我最好寫自己的readLine()方法嗎?如果是這樣,我會很驚訝。

再次感謝!

+0

你給它一個字符串,你回來的字符串。不去愛的種種 ;)? – paulsm4 2012-07-20 20:43:04

+0

不應readLine()阻止EOL字符?我神奇地插入了一個地方? – jasterm007 2012-07-20 20:45:13

+0

+1因爲在閱讀文檔後,我同意你的意見。 readline()方法也應該提到一個行結束符可以是EOF。 – goat 2012-07-20 20:47:39

回答

3

時,它排出的ByteArrayInputStream的不返回EOL。它只返回-1,可能被認爲是EOF。

問題是BufferedReader緩衝了從輸入流中讀取的所有內容,並且如果在任何EOL字符出現之前遇到EOF(-1),它將返回緩衝到該點的字符串。

所以,如果你想要非常嚴格,那麼你可以說readLine()是根據當前文檔或borken,或者如果這是預期的行爲應該被記錄爲不同的文檔。

在我看來,考慮到流中的最後一行不必以EOL字符結尾(EOF足夠),readLine的當前行爲是正確的,即由於遇到EOF而讀取了一行。所以,文檔應該改變。

+0

謝謝。你碰巧有一個關於如何對應該依賴System.in輸入的東西進行單元測試的建議嗎?我試圖測試我的閱讀器是否能夠正確讀取一行,如果我給它一行的一部分,延遲,然後給它的其餘部分,包括EOL。否則,我會發佈一個單獨的問題。 – jasterm007 2012-07-20 22:08:58

+0

如果我理解正確,您希望模擬在System.in上寫入內容時暫停的用戶,然後繼續寫入。 我認爲可以模擬這種行爲的唯一方法是擴展ByteArrayInputStream並重寫read方法,以便在返回下一個字節之前偶爾(或至少一次)睡眠。 – Razvan 2012-07-20 22:27:01

1

我想這會阻止你從真正的流中讀取數據(例如網絡套接字)。但是由於底層輸入是一個數組,讀者知道數據的真實結束已經到達,所以不需要阻塞,因爲沒有新的數據即將到來。所以阻止將是一個錯誤的行動。在讀取實際數據時返回null也是一件錯誤的事情。

+0

我同意,當ByteArrayInputStream在讀取時返回EOF時,阻塞將是錯誤的操作過程。但我不同意null是不正確的返回值。 BufferedReader的目的是爲了緩衝信息,直到它有效地返回它。在這種情況下,readLine()應該已經緩存了「O hai world」。然後在沒有遇到EOL時返回null,因爲實際上沒有讀取行。 – jasterm007 2012-07-20 21:17:25

+0

想到一個文本編輯器。即使文本文件沒有尾隨EOL,在打開文件時仍會看到最後一行文本。如果readLine()以您建議的方式實現,則無法使用它來實現文本編輯器。將文檔更改爲包括EOF作爲行終止條件是IMO,這裏需要什麼。 – 2012-07-20 21:35:41

+0

嗯,這似乎是一個用例BufferedReader。readLine()應該讓你讀取文件中的所有行,但是最後一行,因爲它有一個不完整的行,所以它會返回null,然後你可以使用你最喜歡的BufferedReader.read()來獲得剩下的路。無論如何,感謝您確認您認爲文檔不能反映真實情況。 – jasterm007 2012-07-20 21:50:22

0

這個版本的代碼會發生什麼?

String readString; 
String writeString = "O\nhai\nworld."; 
BufferedReader br = new BufferedReader(
    new InputStreamReader( 
     new ByteArrayInputStream(writeString.getBytes()), 
     "UTF-8"), 
    1024); 
while (true) { 
    readString = br.readLine(); 
    if (readString == null) break; 
    System.out.println("readString: " + readString); 
} 
+0

1)打印「O」,2)打印「海」,3)打破。相反,它會打印「O」,然後是「海」,然後是「世界」。 – jasterm007 2012-07-20 21:53:56

+0

如果「3」中斷「,那麼你永遠不會得到」世界「。這些數據將永遠消失。 readLine()的意義在於將數據分解爲很好的塊或行。但是你仍然應該得到所有的數據,然後你得到空。說得通?是的,文件可能會更清楚。 – 2012-07-20 22:01:59

+0

我仍然不同意,但似乎我在這裏是少數。如果readLine()工作喜歡文檔說它做,那麼它會返回null,我希望BufferedReader仍然有數據緩衝。正如我對德米特里 - 貝蘭斯基所說的那樣,我覺得在這一點上,你可以使用一個普通的read()來獲取其餘的數據,直到你點擊EOF。我猜想很多用例都不方便,但對於我試圖構建的模擬延遲System.in輸入的單元測試非常麻煩。 – jasterm007 2012-07-20 22:12:28

0

現在唯一的選擇是將最後的不完整的線丟掉。不可取。

1

我相信你想有一個「機器人」模擬按鍵用於測試目的:

此類用於生成用於 目的測試的本地系統輸入事件自動化,自運行演示,以及需要控制鼠標和鍵盤的其他應用程序。 Robot的主要目的是促進Java 平臺實現的自動化測試。

下面是進一步討論的一篇文章:

+0

太棒了,謝謝!這可能是一個竅門。 – jasterm007 2012-07-21 20:23:05