BufferedReader和BufferedWriter簡介
為了提高字符流讀寫的效率,引入了緩沖機制,進行字符批量的讀寫,提高了單個字符讀寫的效率。BufferedReader用於加快讀取字符的速度,BufferedWriter用於加快寫入的速度
BufferedReader和BufferedWriter類各擁有8192個字符的緩沖區。當BufferedReader在讀取文本文件時,會先盡量從文件中讀入字符數據並放滿緩沖區,而之后若使用read()方法,會先從緩沖區中進行讀取。如果緩沖區數據不足,才會再從文件中讀取,使用BufferedWriter時,寫入的數據並不會先輸出到目的地,而是先存儲至緩沖區中。如果緩沖區中的數據滿了,才會一次對目的地進行寫出。
BufferedReader
BufferedReader是為了提供讀的效率而設計的一個包裝類,它可以包裝字符流。可以從字符輸入流中讀取文本,緩沖各個字符,從而實現字符、數組和行的高效讀取。
構造方法
方法 描述
BufferedReader(Reader in) 創建一個使用默認大小輸入緩沖區的緩沖字符輸入流。
BufferedReader(Reader in, int sz) 創建一個使用指定大小輸入緩沖區的緩沖字符輸入流。
成員方法
方法 描述
int read() 讀取單個字符。
int read(char[] cbuf, int off, int len) 將字符讀入數組的某一部分。
String readLine() 讀取一個文本行。
long skip(long n) 跳過字符。
boolean ready() 判斷此流是否已准備好被讀取。
void close() 關閉該流並釋放與之關聯的所有資源。
void mark(int readAheadLimit) 標記流中的當前位置。
boolean markSupported() 判斷此流是否支持 mark() 操作(它一定支持)。
void reset() 將流重置到最新的標記。
讀取文件實例
讀取文件: 一個字符一個字符的讀取
int read()方法,每次可以讀取到一個字符(以int 類型表示),不過因為返回的是int類型的,所以要強制類型轉換成char類型才能打印該字符。
public static void printByFileReader(String filePath) throws IOException { BufferedReader reader=new BufferedReader( new FileReader(filePath) ); if(!reader.ready()) { System.out.println("文件流暫時無法讀取"); return; } int result=0; while((result=reader.read())!=-1) { //因為讀取到的是int類型的,所以要強制類型轉換 System.out.print((char)result); } reader.close(); }
讀取文件:一個數組一個數組的讀取
int read(char[] cbuf, int off, int len)方法,每次讀取len個字符放到字符數組cbuf中,從數組cbuf的下表off開始放,返回的是每次讀取的字符個數。
public static void printByFileReaderChars(String filePath) throws IOException { BufferedReader reader=new BufferedReader( new FileReader(filePath) ); if(!reader.ready()) { System.out.println("文件流暫時無法讀取"); return; } int size=0; char[] cbuf=new char[20]; while((size=reader.read(cbuf, 0, cbuf.length))!=-1) { System.out.print(new String(cbuf,0,size)); } reader.close(); }
讀取文件:一行一行的讀取
String readLine()這個方法一次可以讀取一個文本行,返回的直接就是這一行的字符串,如果讀到行尾了就返回null。
public static void printByFileReaderLine(String filePath) throws IOException { BufferedReader reader=new BufferedReader( new FileReader(filePath) ); if(!reader.ready()) { System.out.println("文件流暫時無法讀取"); return; } int size=0; String line; while((line=reader.readLine())!=null) { System.out.print(line+"\n"); } reader.close(); }
需要注意的是:reader.readLine()方法返回的一行字符中不包含換行符,所以輸出的時候要自己加上換行符。
BufferedReader比FileReader高級的地方在於這個,FileReader能一次讀取一個字符,或者一個字符數組。而BufferedReader也可以,同時BufferedReader還能一次讀取一行字符串。同時,BufferedReader帶緩沖,會比FileReader快很多。
但是FileReader使用項目的編碼來讀取解析字符,不能指定編碼,可能會出現編碼問題,如果要指定編碼可以使用包裝InputStreamReader的BufferedReader。這樣兼顧效率和編碼。
測試上述方法:
public static void main(String[] args) throws IOException { String fileutf8="utf8.txt"; String filegbk="gbk.txt"; //一個字符一個字符的讀取 printByFileReader(filegbk); System.out.println("\n---------------------------------------"); //一個字符數組一個字符數組的讀取 printByFileReaderChars(filegbk); System.out.println("\n---------------------------------------"); //一行一行的讀取 printByFileReaderLine(filegbk); System.out.println("#########################################"); //一個字符一個字符的讀取 printByFileReader(fileutf8); System.out.println("\n---------------------------------------"); //一個數組一個數組的讀取 printByFileReaderChars(fileutf8); System.out.println("\n---------------------------------------"); //一行一行的讀取 printByFileReaderLine(fileutf8); }
運行結果:
gbk file 這里是一句中文 --------------------------------------- gbk file 這里是一句中文 --------------------------------------- gbk file 這里是一句中文 ######################################### utf-8 file 榪欓噷鏄竴鍙ヤ腑鏂? --------------------------------------- utf-8 file 榪欓噷鏄竴鍙ヤ腑鏂? --------------------------------------- utf-8 file 榪欓噷鏄竴鍙ヤ腑鏂?
可以看到包裝FileReader的BufferedReader在讀取文件時候如果文件的編碼和項目的編碼不一樣的時候,會出現亂。
亂碼問題
使用包裝InputStreamReader的BufferedReader讀取文件
String file = "utf8.txt"; BufferedReader reader = new BufferedReader( new InputStreamReader(new FileInputStream(file), "utf-8")); char[] cbuf=new char[20]; int size; while((size=reader.read(cbuf, 0, cbuf.length))!=-1) { System.out.println(new String(cbuf,0,size)); }
運行結果:
utf-8 file
這里是一句中文
這里要弄清楚的是BufferedReader只負責讀到它的內部緩沖區中,而解碼的工作是InputStreamReader完成的。
BufferedWriter
BufferedWriter的API:
構造函數:
方法 描述
BufferedWriter(Writer out) 創建一個緩沖字符輸出流,使用默認大小的輸出緩沖區
BufferedWriter(Writer out, int sz) 創建一個緩沖字符輸出流,使用給定大小的輸出緩沖區
成員方法
方法 描述
void write(int c) 寫入單個字符。
void write(char[] cbuf, int off, int len) 寫入字符數組的某一部分。
void write(String s, int off, int len) 寫入字符串的某一部分。
void newLine() 寫入一個行分隔符。
void close() 關閉此流,但要先刷新它。
void flush() 刷新該流的緩沖。
寫文件實例
使用上述三個寫方法寫文件:一個字符一個字符的復制文件
public static void main(String[] args) throws IOException { BufferedWriter writer=new BufferedWriter(new FileWriter("靜夜思.txt")); char ch='床'; //寫入一個字符 writer.write(ch); String next="前明月光,"; char[] nexts=next.toCharArray(); //寫入一個字符數組 writer.write(nexts,0,nexts.length); //寫入換行符 writer.newLine();//寫入換行符 String nextLine="疑是地上霜。"; //寫入一個字符串。 writer.write(nextLine); //關閉流 writer.close(); }
運行結果,靜夜思.txt:
床前明月光,
疑是地上霜。
應用:復制文本文件
逐個字符復制文件
static void copyByChar(String srcFile, String destFile) throws IOException { BufferedReader reader = new BufferedReader(new FileReader(srcFile)); BufferedWriter writer = new BufferedWriter(new FileWriter(destFile)); int ch=0; //讀取一個字符 while ((ch = reader.read()) != -1) { //寫入一個字符 writer.write(ch); } reader.close(); writer.close(); }
逐個字符數組復制文件
static void copyByCharArray(String srcFile, String destFile) throws IOException { BufferedReader reader = new BufferedReader(new FileReader(srcFile)); BufferedWriter writer = new BufferedWriter(new FileWriter(destFile)); int size=0; char[] cbuf=new char[20]; //讀取一個字符數組 while ((size = reader.read(cbuf)) != -1) { //讀入多少寫入多少 writer.write(cbuf,0,size); } reader.close(); writer.close(); }
按行復制文件
static void copyByLine(String srcFile,String destFile) throws IOException { BufferedReader reader=new BufferedReader(new FileReader(srcFile)); BufferedWriter writer=new BufferedWriter(new FileWriter(destFile)); String line; //BufferedReader讀取一行的時候返回的字符串中不包括換行符 //如果有一行字符就返回該行字符串,沒有就返回null while((line=reader.readLine())!=null) { writer.write(line); writer.newLine();//寫換行符 } reader.close(); writer.close(); }
需要注意的是,BufferedReader的readLine()讀取一行的時候返回的字符串沒有換行符,所以,復制的時候寫文件是我們好多寫入一個換行符,使用writer.newLine()方法即可。
測試:
public static void main(String[] args) throws IOException { String from = "gbk.txt"; String to = "gbk_copy.txt"; String to1 = "gbk_copy1.txt"; String to2 = "gbk_copy2.txt"; copyByChar(from, to); copyByCharArray(from, to1); copyByLine(from, to2); }
源文件gbk.txt:
運行結果:
gbk_copy.txt
gbk file
這里是一句中文
gbk_copy1.txt
gbk file
這里是一句中文
gbk_copy2.txt
gbk file
這里是一句中文
bug:按行復制的時候多寫換行符
細心的朋友可能發現,按行復制的時候,復制的文件會莫名其妙的在文件后面多了一個換行符。這是因為我們每次都在讀到的字符串后面寫一個換行符。
解決辦法:在讀到的字符串前面寫換行符,這樣出現新的問題,就是在文件開頭多出了一個空行,所以加入控制語句,在第一行不寫入換行符,第二行后再寫。
static void copyByLine(String srcFile,String destFile) throws IOException { BufferedReader reader=new BufferedReader(new FileReader(srcFile)); BufferedWriter writer=new BufferedWriter(new FileWriter(destFile)); String line; //BufferedReader讀取一行的時候返回的字符串中不包括換行符 //如果有一行字符就返回該行字符串,沒有就返回null boolean flag=false; while((line=reader.readLine())!=null) { if(!flag) { flag=true; writer.write(line); } else { writer.newLine();//寫換行符 writer.write(line); } } reader.close(); writer.close(); }
這樣復制的文件就不會多謝換行符了,保證復制的文件和源文件是一模一樣的。
bug:亂碼問題
因為我們使用的是包裝FileReader的BufferedReader,包裝FileWriter的BufferedWriter。所以讀字符,寫字符的時候使用的是默認的字符編碼讀寫的。所以讀寫文件的時候會出現亂碼,可以使用包裝InputStreamReader的BufferedReader,包裝OutputStreamWriter的BufferedWriter來復制文件,這樣就可以支持各種字符編碼。
實例:gbk編碼的文件復制到utf8編碼的文件中:
static void copyByLineEncoding(String srcFile, String srcEncoding, String destFile, String destEncoding) { BufferedReader reader = null; BufferedWriter writer = null; try { reader = new BufferedReader(new InputStreamReader( new FileInputStream(srcFile), srcEncoding)); writer = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(destFile), destEncoding)); char[] charArray = new char[512]; int size; while ((size = reader.read(charArray, 0, charArray.length)) != -1) { writer.write(charArray, 0, size); } } catch (UnsupportedEncodingException | FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
main方法:
public static void main(String[] args) throws IOException { String from = "gbk.txt"; String to = "copyto_utf8.txt"; copyByLineEncoding(from,"gbk",to,"utf-8"); }
源文件gbk.txt(gbk編碼):
gbk file
這里是一句中文
目標文件copyto_utf8.txt:
utf-8 file
榪欓噷鏄竴鍙ヤ腑鏂�
亂碼是正常的,因為我們的工程目錄用的gbk編碼,把copyto_utf8.txt編碼顯示就好了:
utf-8 file
這里是一句中文
所以使用包裝InputStreamReader的BufferedReader,包裝OutputStreamWriter的BufferedWriter來復制文件的好處就是可以指定復制文件的時候使用的字符編碼,例如上面的復制操作,從gbk編碼的文件中讀取,然后寫入到utf8編碼的文件中去。
————————————————
版權聲明:本文為CSDN博主「藍藍223」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_21808961/article/details/81561464