簡體   English   中英

緩沖區鏈接和裝飾原理 Java I/O

[英]Buffer chaining and decorative principle Java I/O

是的,我知道緩沖區是什么。 但是看這個:

BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("file.txt"));

緩沖在這里實際上是如何工作的? 在我看來,我們在 FileWriter 緩沖區而不是 BufferedWriter 緩沖區中緩沖數據。 因為當 BufferedWriter 的緩沖區滿了它會把它發送到 FileWriter 緩沖區並負責寫入數據?

我錯過了什么嗎? 我的看法:看起來我們正在將水從一個較大的容器中吸到一個較小的容器中。 所以我們最終從較小的那個倒水。

類似的例子在這里:

Scanner scanner = new BufferedReader(new FileReader("file.txt"));
scanner.nextLine();

我到處都看到過這種情況。 實際上,我們最終是逐行讀取掃描儀,而不是從緩沖區及其 8k 容量讀取。 那么這里的緩沖區有什么意義呢? 我們從文件中逐行讀取,而不是一次讀取整個緩沖區。 bufferedReader在這里是冗余的嗎?

請有人能很好地解釋這一點,我已經苦苦掙扎了很長時間。

讀取和寫入數據的低級系統調用經過優化,可以一次傳輸更大的塊。 緩沖讓您可以利用這一點。 當您寫入單個字符或短字符串時,它們會全部累積在一個緩沖區中,並在緩沖區已滿時作為一個大塊寫出。 當您讀取數據時,讀取函數請求填充一個大緩沖區,然后從該緩沖區返回數據。

你是對的,將緩沖流包裝在其他緩沖流中是沒有意義的:充其量它什么也做不了,最壞的情況是它增加了開銷,因為數據被不必要地從一個緩沖區復制到另一個緩沖區。 最靠近數據源的緩沖區最重要。

另一方面, API 規范中沒有任何內容說 FileWriter 和 FileReader 有緩沖區 事實上,它建議將 FileWriter 包裝在 BufferedWriter 中,將FileReader 包裝在 BufferedReader 中

為了獲得最高效率,請考慮將OutputStreamWriter包裝在BufferedWriter中,以避免頻繁調用轉換器。 例如:

 Writer out = new BufferedWriter(new OutputStreamWriter(System.out));

(FileWriter 是 OutputStreamWriter 的子類)

這在內部如何運作?

但是,如果您查看 FileWriter 的實現方式,情況就會變得復雜,因為 FileWriter確實涉及緩沖區。 一些細節可能取決於您使用的 Java 的版本。 在 OpenJDK 中,當您創建一個裝飾 FileWriter 的 BufferedWriter 時:

BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("file.txt"));

您正在創建如下所示的一堆對象,其中一個 object 包裹下一個:

BufferedWriter -> FileWriter -> StreamEncoder -> FileOutputStream

其中StreamEncoder是內部 class,是OutputStreamWriter實現方式的一部分。

現在,當您將字符寫入BufferedWriter實例時,它首先將它們累積在 BufferedWriter 自己的緩沖區中。 在您寫入足夠的數據來填充此緩沖區(或調用flush() )之前,內部FileWriter看不到任何數據。

BufferedWriter緩沖區變滿時,它會通過一次調用write(char[],int,int)將緩沖區的內容寫入FileWriter 這種大數據塊的傳輸是效率的來源:現在 FileWriter 有一個大數據塊可以寫入文件,而不是單個字符。

然后它變得有點復雜:必須將字符轉換為字節,以便將它們寫入文件。 這是 FileWriter 將這些數據傳遞給 StreamEncoder 的地方。

StreamEncoder class 使用CharsetEncoder將字符塊一次全部轉換為字節,並將字節累積在它自己的緩沖區中。 完成后,它將字節作為一個塊寫入最里面的 FileOutputStream。 FileOutputStream 然后調用操作系統函數寫入實際文件。

如果您不使用 BufferedWriter 怎么辦?

如果您直接將字符寫入 FileWriter,它們將傳遞給 StreamEncoder object,后者將它們轉換為字節並存儲在其專用緩沖區中,而不是直接寫入 FileOutputStream。 這樣,FileWriter 的內部實現為您提供了一些緩沖的好處。 但這不是 API 規范的一部分,因此您不應依賴它。

此外,每次調用FileWriter.write都會導致調用 CharsetEncoder 以將字符編碼為字節。 一次編碼大塊字符效率更高,寫入單個字符或短字符串的開銷更高。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM