2017-03-31 35 views
4

我學習Android開發(我在通用編程初學者),並瞭解HTTP網絡和看到這個代碼的教訓:InputStream,InputStreamReader和BufferedReader如何在Java中一起工作?

private String readFromStream(InputStream inputStream) throws IOException { 
    StringBuilder output = new StringBuilder(); 
    if (inputStream != null) { 
    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8")); 
    BufferedReader reader = new BufferedReader(inputStreamReader); 
    String line = reader.readLine(); 
    while (line != null) { 
     output.append(line); 
     line = reader.readLine(); 
    } 
    } 
    return output.toString(); 
} 

我不明白到底是什麼的InputStream,InputStreamReader和BufferedReader類做。它們都有一個read()方法,並且在BufferedReader的情況下也有readLine()。爲什麼我不能只使用InputStream或只添加InputStreamReader?爲什麼我需要添加BufferedReader?我知道這與效率有關,但我不明白。

我一直在研究和documentation for the BufferedReader試圖解釋這一點,但我還是不明白誰在做什麼:

在一般情況下,每個讀請求做了一個讀者會導致相應的 讀請求由底層字符或字節流組成。因此建議使用 將BufferedReader包裝在read()操作可能代價高昂的任何Reader 周圍,例如FileReaders和InputStreamReaders。例如,

BufferedReader in = new BufferedReader(new FileReader("foo.in")); 將緩衝來自指定文件的輸入。如果沒有緩衝,每個調用read()或readLine()都可能導致文件從 中讀取字節,轉換爲字符,然後返回,這可能是效率非常低的 。

所以,我明白的InputStream只能讀一個字節,使用InputStreamReader單個字符,和BufferedReader類一整行,它也確實對一些效率,這是我不明白。我想更好地瞭解誰在做什麼,以便理解爲什麼我需要他們三個人,以及沒有他們中的哪一個會有什麼不同。

我在網上的其他地方研究了很多,似乎沒有找到任何解釋,我可以理解,幾乎所有的教程只是重複文檔信息。這裏有一些相關的問題可能開始解釋這一點,但不要深入並解決我的困惑:Q1,Q2,Q3,Q4。我認爲這可能與最後一個問題關於系統調用和返回的解釋有關。但我想明白這一切是什麼意思。

難道是BufferedReader的readLine()調用InputStreamReader的read()方法,該方法又調用InputStream的read()方法?並且InputStream返回轉換爲int的字節,每次返回一個字節,InputStreamReader讀取足夠的這些數據以生成單個字符並將其轉換爲int並一次返回一個字符,並且BufferedReader讀取足夠多的這些字符用整數表示來組成一個整行?並將整行返回爲String,只返回一次而不是幾次?我不知道,我只是想知道事情是如何運作的。

提前感謝!

+3

http://stackoverflow.com/questions/32175221/what-is-the-relation-between-inputstream-buffreredinputstream-inputstreamreade?rq=1? – 2017-03-31 18:09:17

+0

感謝您的建議@RC。我已經看到了這個問題,並在我自己的問題中提到了這個問題。我正在尋找一些更具體的事情,以瞭解他們之間發生了什麼。 – schv09

回答

10

這個Streams in Java concepts and usage的鏈接,給出了很好的解釋。

This

流,讀者,作者,BufferedReader類,但是BufferedWriter - 這些都是你在Java中處理的術語。Java中提供了用於輸入和輸出操作的類。真正值得了解這些是如何相關的以及如何使用它們。本文將詳細探討Java中的Streams和其他相關類。因此,讓我們開始:

讓我們定義每個這些高層次然後深入挖掘。


用來處理字節級數據

讀/寫
用來對付人物等級。它也支持各種字符編碼。

BufferedReader/BufferedWriter
提高性能。要讀取的數據將被緩存到內存中以便快速訪問。

雖然這些是用於輸入,但只有相應的類也存在輸出。例如,如果有一個InputStream旨在讀取字節流,並且OutputStream將有助於寫入字節流。

InputStreams
java提供了很多類型的InputStreams。每個連接到不同的數據源,如字節數組,文件等。

例如FileInputStream連接到文件數據源,可用於從文件中讀取字節。雖然ByteArrayInputStream可用於將字節數組視爲輸入流。

的OutputStream
這有助於書面字節的數據源。對於幾乎每個InputStream,都有一個對應的OutputStream,無論哪裏合理。


UPDATE

什麼是緩衝流?

在這裏,我從Buffered Streams報價,Java文檔(隨着技術的解釋):

緩衝流

多數時候我們到目前爲止看到使用無緩衝I例子/ O 。這意味着 每個讀或寫請求都由底層操作系統直接處理。 這可能會使程序效率低得多,因爲每個這樣的請求都會觸發磁盤訪問,網絡活動或其他操作相對昂貴的其他操作 。

爲了減少這種開銷,Java平臺實現了緩衝的I/O流。緩衝輸入流從已知爲 的存儲區讀取數據作爲緩衝區;本地輸入API僅在緩衝區爲 爲空時調用。同樣,緩衝輸出流將數據寫入緩衝區,並且僅在緩衝區已滿時才調用本地輸出API。

有時候,我失去了我的頭髮閱讀技術文檔。所以,在這裏我引用了更加人性化的解釋https://yfain.github.io/Java4Kids/

一般情況下,磁盤訪問比處理內存中執行 慢得多;這就是爲什麼訪問磁盤不是一個好主意,要讀取1,000字節的文件一千次。爲了最小化的次數的磁盤訪問次數 ,Java提供緩衝器,其作爲數據的 儲層。

enter image description here

在閱讀文件,然後的FileInputStream的BufferedInputStream,該 類的BufferedInputStream作品的FileInputStream 和文件本身之間的中間人。它從文件中讀取的字節的一大塊成在一杆 存儲器(緩衝器),和的FileInputStream的對象然後 讀取從那裏單個字節,它是快速存儲器到存儲器 操作。 BufferedOutputStream與類 FileOutputStream類似。

這裏的主要思想是儘量減少磁盤訪問。緩衝流 不改變原有數據流的類型 - 他們只是讓閱讀 更有效。一個程序執行流鏈接(或流管道) 來連接流,就像管道連接在管道中一樣。

+2

這是一個很好的答案。我只是想強化Java COULD剛剛提供了一個非常簡單的方法,如:String text = new File(「data.txt」)。getText()來讀取所有文本。事實上,Java 8確實提供了這樣的東西,但總的來說,Java只是給你一些東西,讓你可以以任何你喜歡的方式將它們組合在一起(更接近於Python提供解決問題的單一方式的方法,而不是Ruby的「Make the common簡單的事情和罕見的事情「 - 通常會導致多種方式來解決問題。) –

+0

謝謝,@ישואוהבאותך。我理解圖的前兩部分,InputStreamReader將讀取由InputStream讀取的字節並將它們編碼爲字符。但是我沒有獲得緩衝部分,BufferedReader如何提供幫助?這條線意味着什麼:「爲了提高性能,要讀取的數據將被緩存到內存中以便快速訪問。」它用較少的技術詞彙做什麼? – schv09

+1

大更新,@ישואוהבאותך!謝謝,我只會補充一點,關於這三個類如何一起工作。在進一步閱讀和瀏覽OpenJDK源代碼時,發生了以下情況:BufferedReader負責維護和填充char數組,它的read()或readLine()方法將從這裏獲取字符。它將通過調用InputStreamReader的read(char [],int,int)方法來填充。 InputStreamReader與StreamDecoder相關聯,當它被讀取(char [],int,int)被調用時,它將調用StreamDecoder的read(char [],int,int)。 (1/2) – schv09

1
  • InputStream, OutputStream, byte[], ByteBuffer二進制數據。
  • Reader, Writer, String, char文本,內部是Unicode,所以世界上所有的腳本都可以組合(比如說希臘語和阿拉伯語)。

  • InputStreamReaderOutputStreamWriter在兩者之間形成橋樑。如果你有一些InputStream和知道它的字節實際上是在某些編碼的文字,字符集,那麼你可以用InputStream的:

    try (InputStreamReader reader = 
         new InputStreamReader(stream, StandardCharsets.UTF_8)) { 
        ... read text ... 
    } 
    

有沒有字符集一個構造函數,但這是不可移植的,因爲它使用默認的平臺編碼。

在Android StandardCharset可能不存在,則使用 「UTF-8」。

派生類FileInputStreamBufferedReader爲父項添加內容InputStream resp。 Reader

FileInputStream用於從文件輸入,而BufferedReader使用內存緩衝區,所以實際的物理讀取不會無法讀取字符(低效率)。隨着new BufferedReader(otherReader)你添加緩衝到您的原始讀者。

所有這一切理解,有實用類Files與方法如newBufferedReader(Path, Charset),這增加了更多的簡潔性。

+0

謝謝,@Joop,我仍然沒有得到最後一部分。 BufferReader如何提供幫助?我不明白這一行:BufferReader「將緩衝來自指定文件的輸入,如果沒有緩衝,每次調用read()或readLine()都會導致從文件讀取字節,轉換爲字符,然後返回,這可能非常低效。「這個代碼在我的問題中引用。現在使用BufferedReader時有什麼區別? – schv09

+1

我已經添加了一些你的評論給其他人的答案。解釋說BufferedReader最終從文件中讀取。一個普通的Reader會重複地詢問操作系統讀取一個char /字節並檢查文件結束,在一個循環中。讀取代替緩衝區提高了速度,因爲操作系統內部不使用int read()而是int read(byte [],int,int)。所以它通常是_faster_,儘管用例依賴。功能應該沒有區別。 –

相關問題