JavaIO?BufferedReader和BufferedWriter使用及說(shuō)明
BufferedReader和BufferedWriter簡(jiǎn)介
為了提高字符流讀寫的效率,引入了緩沖機(jī)制,進(jìn)行字符批量的讀寫,提高了單個(gè)字符讀寫的效率。
BufferedReader用于加快讀取字符的速度,BufferedWriter用于加快寫入的速度
BufferedReader和BufferedWriter類各擁有8192個(gè)字符的緩沖區(qū)。當(dāng)BufferedReader在讀取文本文件時(shí),會(huì)先盡量從文件中讀入字符數(shù)據(jù)并放滿緩沖區(qū),而之后若使用read()方法,會(huì)先從緩沖區(qū)中進(jìn)行讀取。
如果緩沖區(qū)數(shù)據(jù)不足,才會(huì)再?gòu)奈募凶x取,使用BufferedWriter時(shí),寫入的數(shù)據(jù)并不會(huì)先輸出到目的地,而是先存儲(chǔ)至緩沖區(qū)中。如果緩沖區(qū)中的數(shù)據(jù)滿了,才會(huì)一次對(duì)目的地進(jìn)行寫出。
BufferedReader
BufferedReader是為了提供讀的效率而設(shè)計(jì)的一個(gè)包裝類,它可以包裝字符流??梢詮淖址斎肓髦凶x取文本,緩沖各個(gè)字符,從而實(shí)現(xiàn)字符、數(shù)組和行的高效讀取。
構(gòu)造方法
方法 | 描述 |
---|---|
BufferedReader(Reader in) | 創(chuàng)建一個(gè)使用默認(rèn)大小輸入緩沖區(qū)的緩沖字符輸入流。 |
BufferedReader(Reader in, int sz) | 創(chuàng)建一個(gè)使用指定大小輸入緩沖區(qū)的緩沖字符輸入流。 |
成員方法
方法 | 描述 |
---|---|
int read() | 讀取單個(gè)字符。 |
int read(char[] cbuf, int off, int len) | 將字符讀入數(shù)組的某一部分。 |
String readLine() | 讀取一個(gè)文本行。 |
long skip(long n) | 跳過(guò)字符。 |
boolean ready() | 判斷此流是否已準(zhǔn)備好被讀取。 |
void close() | 關(guān)閉該流并釋放與之關(guān)聯(lián)的所有資源。 |
void mark(int readAheadLimit) | 標(biāo)記流中的當(dāng)前位置。 |
boolean markSupported() | 判斷此流是否支持 mark() 操作(它一定支持)。 |
void reset() | 將流重置到最新的標(biāo)記。 |
讀取文件實(shí)例
讀取文件: 一個(gè)字符一個(gè)字符的讀取
int read()方法,每次可以讀取到一個(gè)字符(以int 類型表示),不過(guò)因?yàn)榉祷氐氖莍nt類型的,所以要強(qiáng)制類型轉(zhuǎn)換成char類型才能打印該字符。
public static void printByFileReader(String filePath) throws IOException { ? ? BufferedReader reader=new BufferedReader( ? ? ? ? ? ? new FileReader(filePath) ? ? ? ? ? ? ); ? ? if(!reader.ready()) ? ? { ? ? ? ? System.out.println("文件流暫時(shí)無(wú)法讀取"); ? ? ? ? return; ? ? } ? ? int result=0; ? ? while((result=reader.read())!=-1) ? ? { ? ? ? ? //因?yàn)樽x取到的是int類型的,所以要強(qiáng)制類型轉(zhuǎn)換 ? ? ? ? System.out.print((char)result); ? ? } ? ? reader.close(); }
讀取文件:一個(gè)數(shù)組一個(gè)數(shù)組的讀取
int read(char[] cbuf, int off, int len)方法,每次讀取len個(gè)字符放到字符數(shù)組cbuf中,從數(shù)組cbuf的下表off開(kāi)始放,返回的是每次讀取的字符個(gè)數(shù)。
public static void printByFileReaderChars(String filePath) throws IOException { ? ? BufferedReader reader=new BufferedReader( ? ? ? ? ? ? new FileReader(filePath) ? ? ? ? ? ? ); ? ? if(!reader.ready()) ? ? { ? ? ? ? System.out.println("文件流暫時(shí)無(wú)法讀取"); ? ? ? ? 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()這個(gè)方法一次可以讀取一個(gè)文本行,返回的直接就是這一行的字符串,如果讀到行尾了就返回null。
public static void printByFileReaderLine(String filePath) throws IOException { ? ? BufferedReader reader=new BufferedReader( ? ? ? ? ? ? new FileReader(filePath) ? ? ? ? ? ? ); ? ? if(!reader.ready()) ? ? { ? ? ? ? System.out.println("文件流暫時(shí)無(wú)法讀取"); ? ? ? ? return; ? ? } ? ? int size=0; ? ? String line; ? ? while((line=reader.readLine())!=null) ? ? { ? ? ? ? System.out.print(line+"\n"); ? ? } ? ? reader.close(); }
需要注意的是:reader.readLine()方法返回的一行字符中不包含換行符,所以輸出的時(shí)候要自己加上換行符。
BufferedReader比FileReader高級(jí)的地方在于這個(gè),F(xiàn)ileReader能一次讀取一個(gè)字符,或者一個(gè)字符數(shù)組。而B(niǎo)ufferedReader也可以,同時(shí)BufferedReader還能一次讀取一行字符串。同時(shí),BufferedReader帶緩沖,會(huì)比FileReader快很多。
但是FileReader使用項(xiàng)目的編碼來(lái)讀取解析字符,不能指定編碼,可能會(huì)出現(xiàn)編碼問(wèn)題,如果要指定編碼可以使用包裝InputStreamReader的BufferedReader。這樣兼顧效率和編碼。
測(cè)試上述方法:
public static void main(String[] args) throws IOException { ? ? String fileutf8="utf8.txt"; ? ? String filegbk="gbk.txt"; ? ? //一個(gè)字符一個(gè)字符的讀取 ? ? printByFileReader(filegbk); ? ? System.out.println("\n---------------------------------------"); ? ? //一個(gè)字符數(shù)組一個(gè)字符數(shù)組的讀取 ? ? printByFileReaderChars(filegbk); ? ? System.out.println("\n---------------------------------------"); ? ? //一行一行的讀取 ? ? printByFileReaderLine(filegbk); ? ? System.out.println("#########################################"); ? ? //一個(gè)字符一個(gè)字符的讀取 ? ? printByFileReader(fileutf8); ? ? System.out.println("\n---------------------------------------"); ? ? //一個(gè)數(shù)組一個(gè)數(shù)組的讀取 ? ? printByFileReaderChars(fileutf8); ? ? System.out.println("\n---------------------------------------"); ? ? //一行一行的讀取 ? ? printByFileReaderLine(fileutf8); }
運(yùn)行結(jié)果:
gbk file
這里是一句中文
---------------------------------------
gbk file
這里是一句中文
---------------------------------------
gbk file
這里是一句中文
#########################################
utf-8 file
榪欓噷鏄竴鍙ヤ腑鏂?
---------------------------------------
utf-8 file
榪欓噷鏄竴鍙ヤ腑鏂?
---------------------------------------
utf-8 file
榪欓噷鏄竴鍙ヤ腑鏂?
可以看到包裝FileReader的BufferedReader在讀取文件時(shí)候如果文件的編碼和項(xiàng)目的編碼不一樣的時(shí)候,會(huì)出現(xiàn)亂。
亂碼問(wèn)題
使用包裝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)); }
運(yùn)行結(jié)果:
utf-8 file
這里是一句中文
這里要弄清楚的是BufferedReader只負(fù)責(zé)讀到它的內(nèi)部緩沖區(qū)中,而解碼的工作是InputStreamReader完成的。
BufferedWriter
BufferedWriter的API:
構(gòu)造函數(shù)
方法 | 描述 |
---|---|
BufferedWriter(Writer out) | 創(chuàng)建一個(gè)緩沖字符輸出流,使用默認(rèn)大小的輸出緩沖區(qū) |
BufferedWriter(Writer out, int sz) | 創(chuàng)建一個(gè)緩沖字符輸出流,使用給定大小的輸出緩沖區(qū) |
成員方法
方法 | 描述 |
---|---|
void write(int c) | 寫入單個(gè)字符。 |
void write(char[] cbuf, int off, int len) | 寫入字符數(shù)組的某一部分。 |
void write(String s, int off, int len) | 寫入字符串的某一部分。 |
void newLine() | 寫入一個(gè)行分隔符。 |
void close() | 關(guān)閉此流,但要先刷新它。 |
void flush() | 刷新該流的緩沖。 |
寫文件實(shí)例
使用上述三個(gè)寫方法寫文件:一個(gè)字符一個(gè)字符的復(fù)制文件
public static void main(String[] args) throws IOException { BufferedWriter writer=new BufferedWriter(new FileWriter("靜夜思.txt")); char ch='床'; //寫入一個(gè)字符 writer.write(ch); String next="前明月光,"; char[] nexts=next.toCharArray(); //寫入一個(gè)字符數(shù)組 writer.write(nexts,0,nexts.length); //寫入換行符 writer.newLine();//寫入換行符 String nextLine="疑是地上霜。"; //寫入一個(gè)字符串。 writer.write(nextLine); //關(guān)閉流 writer.close(); }
運(yùn)行結(jié)果,靜夜思.txt:
床前明月光,
疑是地上霜。
應(yīng)用:復(fù)制文本文件
逐個(gè)字符復(fù)制文件
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; ? ? //讀取一個(gè)字符 ? ? while ((ch = reader.read()) != -1) ? ? { ? ? ? ? //寫入一個(gè)字符 ? ? ? ? writer.write(ch); ? ? } ? ? reader.close(); ? ? writer.close(); }
逐個(gè)字符數(shù)組復(fù)制文件
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]; ? ? //讀取一個(gè)字符數(shù)組 ? ? while ((size = reader.read(cbuf)) != -1) ? ? { ? ? ? ? //讀入多少寫入多少 ? ? ? ? writer.write(cbuf,0,size); ? ? } ? ? reader.close(); ? ? writer.close(); }
按行復(fù)制文件
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讀取一行的時(shí)候返回的字符串中不包括換行符 ? ? //如果有一行字符就返回該行字符串,沒(méi)有就返回null ? ? while((line=reader.readLine())!=null) ? ? { ? ? ? ? writer.write(line); ? ? ? ? writer.newLine();//寫換行符 ? ? } ? ? reader.close(); ? ? writer.close(); }
需要注意的是,BufferedReader的readLine()讀取一行的時(shí)候返回的字符串沒(méi)有換行符,所以,復(fù)制的時(shí)候?qū)懳募俏覀兒枚鄬懭胍粋€(gè)換行符,使用writer.newLine()方法即可。
測(cè)試
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:
運(yùn)行結(jié)果:
gbk_copy.txt
gbk file
這里是一句中文
gbk_copy1.txt
gbk file
這里是一句中文
gbk_copy2.txt
gbk file
這里是一句中文
bug:按行復(fù)制的時(shí)候多寫換行符
細(xì)心的朋友可能發(fā)現(xiàn),按行復(fù)制的時(shí)候,復(fù)制的文件會(huì)莫名其妙的在文件后面多了一個(gè)換行符。這是因?yàn)槲覀兠看味荚谧x到的字符串后面寫一個(gè)換行符。
解決辦法:在讀到的字符串前面寫換行符,這樣出現(xiàn)新的問(wèn)題,就是在文件開(kāi)頭多出了一個(gè)空行,所以加入控制語(yǔ)句,在第一行不寫入換行符,第二行后再寫。
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讀取一行的時(shí)候返回的字符串中不包括換行符 ? ? //如果有一行字符就返回該行字符串,沒(méi)有就返回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(); }
這樣復(fù)制的文件就不會(huì)多謝換行符了,保證復(fù)制的文件和源文件是一模一樣的。
bug:亂碼問(wèn)題
因?yàn)槲覀兪褂玫氖前bFileReader的BufferedReader,包裝FileWriter的BufferedWriter。所以讀字符,寫字符的時(shí)候使用的是默認(rèn)的字符編碼讀寫的。
所以讀寫文件的時(shí)候會(huì)出現(xiàn)亂碼,可以使用包裝InputStreamReader的BufferedReader,包裝OutputStreamWriter的BufferedWriter來(lái)復(fù)制文件,這樣就可以支持各種字符編碼。
實(shí)例:gbk編碼的文件復(fù)制到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
這里是一句中文
目標(biāo)文件copyto_utf8.txt:
utf-8 file
榪欓噷鏄竴鍙ヤ腑鏂?
亂碼是正常的,因?yàn)槲覀兊墓こ棠夸浻玫膅bk編碼,把copyto_utf8.txt編碼顯示就好了:
utf-8 file
這里是一句中文
所以使用包裝InputStreamReader的BufferedReader,包裝OutputStreamWriter的BufferedWriter來(lái)復(fù)制文件的好處就是可以指定復(fù)制文件的時(shí)候使用的字符編碼,例如上面的復(fù)制操作,從gbk編碼的文件中讀取,然后寫入到utf8編碼的文件中去。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決java.net.SocketTimeoutException: Read timed out的問(wèn)題
這篇文章主要介紹了解決java.net.SocketTimeoutException: Read timed out的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06Java并發(fā)編程this逃逸問(wèn)題總結(jié)
本篇文章給大家詳細(xì)分析了Java并發(fā)編程this逃逸的問(wèn)題分享,對(duì)此有需要的朋友參考下。2018-02-02SpringBoot框架RESTful接口設(shè)置跨域允許
這篇文章主要為大家詳細(xì)介紹了SpringBoot框架RESTful接口設(shè)置跨域允許,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08SpringBoot實(shí)現(xiàn)設(shè)置全局和局部時(shí)間格式化
本文主要介紹了SpringBoot實(shí)現(xiàn)設(shè)置全局和局部時(shí)間格式化,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01Java并發(fā)中線程封閉知識(shí)點(diǎn)詳解
在本篇文章里我們給大家整理了關(guān)于Java并發(fā)中線程封閉的知識(shí)點(diǎn)總結(jié)內(nèi)容,需要的朋友們學(xué)習(xí)參考下。2019-07-07Java中null的意義及其使用時(shí)的注意事項(xiàng)說(shuō)明
這篇文章主要介紹了Java中null的意義及其使用時(shí)的注意事項(xiàng)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09