日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java 文件缓冲区_Java开发笔记(八十六)通过缓冲区读写文件

發布時間:2023/12/2 java 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 文件缓冲区_Java开发笔记(八十六)通过缓冲区读写文件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面介紹了利用文件寫入器和文件讀取器來讀寫文件,因為FileWriter與FileReader讀寫的數據以字符為單位,所以這種讀寫文件的方式被稱作“字符流I/O”,其中字母I代表輸入Input,字母O代表輸出Output。可是FileWriter的讀操作并不高效,緣由在于FileWriter每次調用write方法都會直接寫入文件,假如某項業務需要多次調用write方法,那么程序就會寫入文件同樣次數。因為寫文件本質是寫磁盤,磁盤的速度遠不如內存,所以頻繁地寫文件必然嚴重降低程序的運行效率。為此Java又設計了緩存寫入器BufferedWriter,它的write方法并不直接寫入文件,而是先寫入一塊緩存,等到緩存寫滿了再將緩存上的數據寫入文件。由于緩存空間位于內存之中,寫入緩存等同訪問內存,這樣相當于把寫磁盤動作替換成寫內存動作,因此BufferedWriter的整體寫文件性能要大大優于FileWriter。除此之外,BufferedWriter還新增了下列幾個方法:

newLine:往文件末尾添加換行標記(Window系統是回車加換行)。當然實際上是先往緩存添加換行標記,并非直接往磁盤寫入換行標記。

flush:立即將緩沖區中的數據寫入磁盤。默認情況要等緩沖區滿了才會寫入磁盤,或者調用close方法關閉文件之時也會寫入磁盤,但是有時程序猴急,一定要立即寫入磁盤,此時就需調用flush方法強行寫磁盤。

使用緩存寫入器之前要先創建文件讀取器對象,并獲得父類Writer的實例,然后再據此創建緩存寫入器對象。下面是通過緩存寫入器把多行字符串寫入文件的代碼例子:

private static String mSrcName = "D:/test/aad.txt";

// 使用緩存字符流寫入文件

private static void writeBuffer() {

String str1 = "白日依山盡,黃河入海流。";

String str2 = "欲窮千里目,更上一層樓。";

File file = new File(mSrcName); // 創建一個指定路徑的文件對象

// try(...)允許在圓括號內部擁有多個資源創建語句,語句之間以冒號分隔

// 先創建文件寫入器,再根據文件讀取器創建緩存寫入器

try (Writer writer = new FileWriter(file);

BufferedWriter bwriter = new BufferedWriter(writer);) {

// FileWriter的每次write調用都會直接寫入磁盤,不但效率低,性能也差。

// BufferedWriter的每次write調用會先寫入緩沖區,直到緩沖區滿了才寫入磁盤,

// 緩沖區大小默認是8K,查看源碼defaultCharBufferSize = 8192;

// 資源釋放的close方法再把緩沖區的剩余數據寫入磁盤,

// 或者中途調用flush方法也可提前將緩沖區的數據寫入磁盤。

bwriter.write(str1); // 往文件寫入字符串

bwriter.newLine(); // 另起一行,也就是在文件末尾添加換行標記(Window系統是回車加換行)

bwriter.write(str2); // 往文件寫入字符串

//bwriter.flush(); // 把緩沖區中的數據寫入磁盤

} catch (Exception e) {

e.printStackTrace();

}

}

既然文件寫入器有對應的緩存寫入器,那么文件讀取器也有對應的緩存讀取器BufferedReader。BufferedReader的實現原理與它的兄弟BufferedWriter類似,另外BufferedReader比起文件讀取器新增了如下方法:

readLine:從文件中讀取一行數據。

mark:在當前位置做個標記。

reset:重置文件指針,令其回到上次標記的位置。也就是回到上次mark方法標記的文件位置。

lines:讀取文件內容的所有行,返回的是Stream流對象,之后便可按照流式處理來加工該字符串流。

若想使用緩存讀取器,依然要先創建文件讀取器,再根據其父類的讀取器實例創建緩存讀取器。下面是通過緩存讀取器從文件中讀取多行字符串的代碼例子:

// 使用緩存字符流讀取文件

private static void readBuffer() {

File file = new File(mSrcName); // 創建一個指定路徑的文件對象

// try(...)允許在圓括號內部擁有多個資源創建語句,語句之間以冒號分隔

// 先創建文件讀取器,再根據文件讀取器創建緩存讀取器

try (Reader reader = new FileReader(file);

BufferedReader breader = new BufferedReader(reader);) {

breader.mark((int) file.length()); // 做個標記

for (int i=1; ; i++) {

// FileReader只能一個字符一個字符地讀,或者一次性讀進字符數組。

// BufferedReader還支持一行一行地讀。

String line = breader.readLine(); // 從文件中讀出一行文字

if (line == null) { // 讀到了空指針,表示已經到了文件末尾

break;

}

System.out.println("第"+i+"行的文字為:"+line);

}

breader.reset(); // 重置文件指針,令其回到上次標記的位置

for (int i=1; ; i++) {

String line = breader.readLine(); // 從文件中讀出一行文字

if (line == null) { // 讀到了空指針,表示已經到了文件末尾

break;

}

System.out.println("又讀了一遍 第"+i+"行的文字為:"+line);

}

//breader.lines(); // 返回Stream對象,之后可按照流式處理來加工該字符串流

} catch (Exception e) {

e.printStackTrace();

}

}

注意到以上代碼BufferedWriter和BufferedReader的創建語句都位于try后面的圓括號之中,這是因為Writer與Reader兩大家族統統實現了AutoCloseable接口,所以由它們繁衍而來的所有子類都具備自動釋放資源的功能。另外,try語句支持同時管理多個資源類,只要它們的對象創建語句以冒號隔開,程序在運行時即可自動回收相關的資源。

結合運用讀操作和寫操作,可以實現文件復制的功能,無非是一邊從源文件中讀出數據,另一邊緊接著往目標文件寫入數據。采用緩存讀取器和緩存寫入器逐行復制的話,具體的文件復制代碼示例如下:

private static String mSrcName = "D:/test/aad.txt";

private static String mDestName = "D:/test/aad_copy.txt";

// 通過緩存字符流逐行復制文件

private static void copyFile() {

File src = new File(mSrcName); // 創建一個指定路徑的源文件對象

File dest = new File(mDestName); // 創建一個指定路徑的目標文件對象

// try(...)允許在圓括號內部擁有多個資源創建語句,語句之間以冒號分隔

// 分別創建源文件的緩存讀取器,以及目標文件的緩存寫入器

try (BufferedReader breader = new BufferedReader(new FileReader(src));

BufferedWriter bwriter = new BufferedWriter(new FileWriter(dest));) {

for (int i=0; ; i++) {

String line = breader.readLine(); // 從文件中讀出一行文字

if (line == null) { // 讀到了空指針,表示已經到了文件末尾

break;

}

if (i != 0) { // 第一行開頭不用換行

bwriter.newLine(); // 另起一行,也就是在文件末尾添加換行標記

}

bwriter.write(line); // 往文件寫入字符串

}

} catch (Exception e) {

e.printStackTrace();

}

System.out.println("文件復制完成,源文件大小="+src.length()+",新文件大小="+dest.length());

}

或者也可逐個字符來復制文件,此時BufferedReader每次調用的read方法只返回整型數表示一個字符,并且BufferedWriter每次調用的write方法也只寫入該字符對應的整型數。通過依次遍歷源文件的所有字符,同時往目標文件依次寫入這些字符,從而完成逐個字符復制文件的操作流程。下面是采取逐字符復制文件的代碼例子:

// 通過緩存字符流逐個字符復制文件

private static void copyFileByInt() {

File src = new File(mSrcName); // 創建一個指定路徑的源文件對象

File dest = new File(mDestName); // 創建一個指定路徑的目標文件對象

// try(...)允許在圓括號內部擁有多個資源創建語句,語句之間以冒號分隔

// 分別創建源文件的緩存讀取器,以及目標文件的緩存寫入器

try (BufferedReader breader = new BufferedReader(new FileReader(src));

BufferedWriter bwriter = new BufferedWriter(new FileWriter(dest));) {

while (true) { // 開始遍歷文件中的所有字符

int temp = breader.read(); // 從源文件中讀出一個字符

if (temp == -1) { // read方法返回-1表示已經讀到了文件末尾

break;

}

bwriter.write(temp); // 往目標文件寫入一個字符

}

} catch (Exception e) {

e.printStackTrace();

}

System.out.println("文件復制完成,源文件大小="+src.length()+",新文件大小="+dest.length());

}

需要注意的是,使用字符流復制文件只有逐行復制和逐字符復制兩種方式,不可采取整個讀到字符數組再整個寫入字符數組的方式。之所以不能通過字符數組復制文件,是因為中文跟英文不一樣,一個漢字會占用多個字節(GBK編碼的每個漢字占用兩個字節,UTF8編碼的每個漢字占用三個字節)。若要把文件內容讀到字符數組,勢必先得知曉該數組的長度,可是調用文件對象的length方法只能得到該文件的字節長度,并非字符長度。譬如“白日依山盡”這個字符串在內存中的字符數組長度為5,寫到UTF8編碼的文件之后,文件大小是5*3=15字節;接著想把文件內容讀到字符數組,然而15字節的文件天曉得它有幾個字符,可能有5個UTF8編碼的中文字符,也可能有15個英文字符,也可能有5個GBK編碼的中文字符加5個英文字符共10個字符,總之你根本想不到該分配多大的字符數組。既然確定不了待讀取的字符數組長度,就無法一字不差地復制文件內容了。

總結

以上是生活随笔為你收集整理的java 文件缓冲区_Java开发笔记(八十六)通过缓冲区读写文件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。