[英]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 然后調用操作系統函數寫入實際文件。
如果您直接將字符寫入 FileWriter,它們將傳遞給 StreamEncoder object,后者將它們轉換為字節並存儲在其專用緩沖區中,而不是直接寫入 FileOutputStream。 這樣,FileWriter 的內部實現為您提供了一些緩沖的好處。 但這不是 API 規范的一部分,因此您不應依賴它。
此外,每次調用FileWriter.write
都會導致調用 CharsetEncoder 以將字符編碼為字節。 一次編碼大塊字符效率更高,寫入單個字符或短字符串的開銷更高。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.