1.本文概述
本文講解IO系列有關字符流對象部分的內容。
字符流主要包含以下四個組成對象:
FileReader
FileWriter
BufferedReader
BufferedWriter
2.Writer部分
1.Writer概述
常用方法:
abstract void close()
關閉此流,但要先刷新它。即會在關閉前先調用flush方法。
abstract void flush()
刷新該流的緩衝。
void write(char[] cbuf)
寫入字符數組。
abstract void write(char[] cbuf, int off, int len)
寫入字符數組的某一部分。
void write(int c)
寫入單個字符。
void write(String str)
寫入字符串。
void write(String str, int off, int len)
寫入字符串的某一部分。
說明:Writer是一個抽象類,無法直接實例化,因此一般使用其間接子類FileWriter。
2.FileWriter
FileWriter概述
FileWriter是用來寫入字符文件的便捷類
常用構造方法:
FileWriter(File file)
根據給定的 File 對象構造一個 FileWriter 對象。
FileWriter(File file, boolean append)
根據給定的 File 對象構造一個 FileWriter 對象。如果append爲true,則將數據寫入文件末尾處,而不是覆蓋整個文件。
說明:關於參數中的File對象部分知識將在後續博文中講解,具體可參考:
FileWriter(String fileName)
根據給定的文件名構造一個 FileWriter 對象。
FileWriter(String fileName, boolean append)
根據給定的文件名以及指示是否附加寫入數據的boolean值來構造 FileWriter 對象。如果append爲true,則將數據寫入文件末尾處,而不是覆蓋整個文件。
說明:FileWriter的方法與Writer中的方法一致,並沒有特有方法,此處不再對其方法進行列舉。
向文件中寫出數據
本例中用到的構造方法:
FileWriter(String fileName)
根據給定的文件名構造一個 FileWriter 對象。
說明:在表示文件路徑時,分隔符需要使用雙反斜槓”\”
步驟:
1.創建一個FileWriter對象,該對象初始化時必須要明確被操作的文件,並且該文件會被創建到指定目錄下。若該目錄下已有同名文件,則該文件將被覆蓋。
2.調用write方法將字符串寫入流中
3.刷新流對象中的緩衝數據,將數據寫入目標文件中
說明:輸出流在關閉前可以多次調用write
以及flush
方法
4.關閉流
說明:該方法會在關閉流前先調用flush方法刷新緩存,調用後流就被徹底關閉了。
示例代碼:
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) {
try {
//實例化字符輸出流對象
FileWriter fw=new FileWriter("G:\\test.txt");
//向指定文件中輸出數據
fw.write("test:");
fw.write("這是一份測試文件");
//刷新流緩存
fw.flush();
//關閉流
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
程序運行結果
1.png
3.IO異常處理方式
與輸入輸出流相關的操作都可能拋出IOException異常,這需要我們進行一些合適的異常處理。
以下爲一個標準的IOException處理示例:
示例代碼:
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) {
//聲明字符輸出流對象並初始化
FileWriter fw=null;
try {
//實例化字符輸出流對象
fw=new FileWriter("G:\\test.txt",true);
//向指定文件中輸出數據
fw.write("\r\ntest:這是在原有基礎上添加數據!");
//刷新流緩存
fw.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
//當fw存在時才關閉流,防止空指針異常
if(fw!=null)
try {
//關閉流
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.對已存在的文件進行續寫
使用FileWriter另一個構造方法:
FileWriter(String fileName, boolean append)
根據給定的文件名以及指示是否附加寫入數據的 boolean 值來構造 FileWriter 對象。
說明:當append傳入參數爲true時,表示不覆蓋已有的文件,而在已有文件的末尾續寫數據。
示例代碼:
//部分代碼
public static void main(String[] args) {
//聲明字符輸出流對象並初始化
FileWriter fw=null;
try {
//實例化字符輸出流對象
fw=new FileWriter("G:\\test.txt",true);
//向指定文件中輸出數據
fw.write("\r\ntest:這是在原有基礎上添加數據!");
//刷新流緩存
fw.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
//當fw存在時才關閉流,防止空指針異常
if(fw!=null)
try {
//關閉流
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
程序運行結果:
2.png
小技巧:如果想要實現文本換行的效果,可以使用轉義字符”\n”,但爲了使windows下的記事本識別換行操作,需要使用”\r\n”
3.Reader部分
1.Reader概述
常用方法:
abstract void close()
關閉該流並釋放與之關聯的所有資源。
int read()
讀取單個字符。如果已到達流的末尾,則返回-1
int read(char[] cbuf)
將字符讀入數組。如果已到達流的末尾,則返回-1
abstract int read(char[] cbuf, int off, int len)
將字符讀入數組的某一部分。如果已到達流的末尾,則返回-1。off是開始位置的索引,len是要讀取的最大字符數
long skip(long n)
跳過字符int read(CharBuffer target)
試圖將字符讀入指定的字符緩衝區。如果已到達流的末尾,則返回-1 。
void reset()
重置該流。
說明:Reader是一個抽象類,無法直接實例化,因此一般使用其間接子類FileReader。
2.FileReader
FileReader概述
FileReader用來讀取字符文件的便捷類。
構造方法:
FileReader(File file)
在給定從中讀取數據的 File 的情況下創建一個新 FileReader。
FileReader(String fileName)
在給定從中讀取數據的文件名的情況下創建一個新 FileReader。
說明:FileWriter的方法與Writer中的方法一致,並沒有特有方法,此處不再對其方法進行列舉。
第一種文本文件讀取方式
通過讀取單個字節的方式獲得文件中的所有數據。
步驟:
1.創建一個文件讀取流對象,和指定名稱的文件相關聯。如果文件不存在,則會拋出FileNotFoundException
2.調用讀取流對象的read方法
fr.read();
說明:當read
方法讀取到流的末尾時,該方法返回-1。利用這一特點,可以通過while循環輸出文件中的所有數據。
示例代碼:
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo {
public static void main(String[] args) {
FileReader fr=null;
try {
//實例化指向已存在文件的輸入流對象
fr=new FileReader("G:\\test.txt");
int ch=0;
while((ch=fr.read())!=-1){
//將獲取到的int型數據強轉爲char型輸出
System.out.print((char)ch);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(fr!=null)
try {
//關閉流
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
程序運行結果:
test:這是一份測試文件
test:這是在原有基礎上添加數據!
第二種文本文件讀取方式
通過字符數組對文件中的數據進行讀取。
步驟:
1.定義一個字符數組,用於存儲讀到的字符
2.創建一個文件輸入流對象
3.通過read(char[])
方法將文件數據讀入指定數組
說明:同樣利用read
方法讀取完畢返回-1的特性,可以使用while循環讀取文件中的全部數據。注意要對獲取到的數組進行有效範圍截取,因爲在循環的最後一次數據讀取中,數組不一定被填滿。此外,爲了保持較高的讀取效率,建議將用於接受數據的字符數組大小定義爲1024的整數倍。
示例代碼:
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo {
public static void main(String[] args) {
FileReader fr=null;
try {
//實例化指向已存在文件的輸入流對象
fr=new FileReader("G:\\test.txt");
//定義用於臨時存儲數據的字符數組
char[] bufArr=new char[1024];
//存儲讀取到的字節長度
int len;
while((len=fr.read(bufArr))!=-1){
//將獲取到的char數組轉化爲字符串,注意對字符數組有效區域的截取
String endStr=new String(bufArr,0,len);
System.out.print(endStr);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(fr!=null)
try {
//關閉流
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
程序運行結果:
test:這是一份測試文件
test:這是在原有基礎上添加數據!
說明:向控制檯中打印數據時應該使用print方法,否則可能在錯誤的位置進行換行,影響輸出效果
總結:以上兩種方法推薦使用第二種。第二種方式由於具有字符數組作爲緩衝區,相比之下讀取效率更高
3.簡單應用-複製文本文件
需求描述:將一個文本文件從E盤複製到D盤
複製的原理:其實就是將E盤下的文件數據讀取後,輸出到到D盤的指定文件中
步驟:
1.在D盤創建一個文件,用於存儲E盤的文件數據
2.定義輸入輸出流和E盤指定文件關聯
3.通過不斷的讀寫完成數據存儲
4.關閉流資源
第一種方式
示例代碼:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyDemo {
public static void main(String[] args) {
FileWriter fw=null;
FileReader fr=null;
try {
//實例化輸入輸出流
fr=new FileReader("E:\\demo.txt");
fw=new FileWriter("D:\\demo.txt");
//將讀取到的數據寫入目標文件
int ch=0;
while((ch=fr.read())!=-1){
fw.write(ch);
//刷新流緩存
fw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
finally{
//關閉資源
if(fr!=null)
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
if(fw!=null)
try {
//關閉流
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
說明:每次讀取一個字符就寫入一個字符,效率較低。因此不建議使用這種方式。但如果目標文件較小倒也無所謂。
第二種方式
本例用到的方法:
int read(char[] cbuf)
將字符讀入數組。如果已到達流的末尾,則返回 -1
abstract void write(char[] cbuf, int off, int len)
寫入字符數組的某一部分。
示例代碼:
public static void main(String[] args) {
FileWriter fw=null;
FileReader fr=null;
try {
//實例化輸入輸出流
fr=new FileReader("E:\\demo.txt");
fw=new FileWriter("D:\\demo.txt");
//定義用於臨時存儲數據的字符數組
char[] bufArr=new char[1024];
//存儲讀取到的字節長度
int len=0;
while((len=fr.read(bufArr))!=-1){
//將字符數組的有效範圍寫入目標文件
fw.write(bufArr,0,len);
//刷新流緩存
fw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
finally{
//關閉資源
if(fr!=null)
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
if(fw!=null)
try {
//關閉流
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
說明:這種方式的效率較高,推薦使用
4.緩衝字符流
1.緩衝字符流概述
- 緩衝區的出現提高了對數據的讀寫效率
- 緩衝區要結合流纔可以使用
- 緩衝流在流的基礎上對流的功能進行了增強。
對應類:
BufferedWriter
BufferedReader
使用的緩衝區的時候的需要注意以下兩點:
1.在使用緩衝區之前必須先有流對象,並將流對象作爲參數構造一個緩衝區對象。
2.使用緩衝區時,一定要使用flush
方法。另外,關閉緩衝區實際上就是關閉緩衝區中的流對象,因此在使用close
對緩衝區進行關閉後,可以不必對流對象再調用close
方法進行關閉。
2.BufferedWriter
BufferedWriter用於將文本寫入字符輸出流,緩衝各個字符,從而提供單個字符、數組和字符串的高效寫入.可以指定緩衝區的大小,或者接受默認的大小。在大多數情況下,默認值就足夠大了。
構造方法:
BufferedWriter(Writer out)
創建一個使用默認大小輸出緩衝區的緩衝字符輸出流。
BufferedWriter(Writer out, int sz)
創建一個使用給定大小輸出緩衝區的新緩衝字符輸出流。
常用方法:
void close()
關閉此流,但要先刷新它。
void flush()
刷新該流的緩衝。
void newLine()
寫入一個行分隔符,即換行符。並且該操作是跨平臺的。
void write(char[] cbuf)
寫入字符數組。
void write(char[] cbuf, int off, int len)
寫入字符數組的某一部分。
void write(int c)
寫入單個字符。
void write(String str)
寫入字符串。
void write(String s, int off, int len)
寫入字符串的某一部分。
示例代碼:
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufWriterDemo {
public static void main(String[] args) {
BufferedWriter bw=null;
try {
//通過傳入FileWriter對象實例化BufferedWriter
bw=new BufferedWriter(new FileWriter("G:\\buf_test.txt"));
bw.write("test:這是通過緩衝流寫入的數據");
//通過緩衝流的特有方法寫入換行符
bw.newLine();
bw.write("test:通過緩衝流的方法寫入了換行符");
//刷新流的緩存
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(bw!=null)
try {
//關閉流
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
程序運行結果:
3.png
3.BufferedReader
BufferedReader用於從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。
構造方法:
BufferedReader(Reader in)
創建一個使用默認大小輸入緩衝區的緩衝字符輸入流。
BufferedReader(Reader in, int sz)
創建一個使用指定大小輸入緩衝區的緩衝字符輸入流。
常用方法:
void close()
關閉該流並釋放與之關聯的所有資源。
int read()
讀取單個字符。
int read(char[] cbuf, int off, int len)
將字符讀入數組的某一部分。
String readLine()
讀取一個文本行,包含該行內容的字符串,不包含任何行終止符。如果已到達流末尾,則返回 null。
long skip(long n)
跳過字符。
void reset()
將流重置到最新的標記。
示例代碼:
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class BufReaderDemo {
public static void main(String[] args) {
BufferedReader br=null;
try {
////通過傳入FileReader對象實例化BufferedReader
br=new BufferedReader(new FileReader("G:\\buf_test.txt"));
String str=null;
while((str=br.readLine())!=null){
//注意要使用println輸出獲取到的數據
System.out.println(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(br!=null)
try {
//關閉流
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
程序運行結果:
test:這是通過緩衝流寫入的數據
test:通過緩衝流的方法寫入了換行符
說明:對於獲取的每行數據,需要通過println輸出,因爲readLine()返回的字符串中不包含換行符。
4.通過緩衝區複製文本文件
需求描述: 通過緩衝區將E盤指定文件複製到D盤
通過readLine()
和writeLine()
方法高效率讀取和寫出
注意:輸出時使用newLine()方法寫出換行符,因爲readLine()返回的字符串中不包含換行符,只返回有效內容。
示例代碼:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class BufCopyDemo {
public static void main(String[] args) {
BufferedWriter bw=null;
BufferedReader br=null;
try {
//實例化輸入輸出緩衝流
bw=new BufferedWriter(new FileWriter("D:\\buf_demo.txt"));
br=new BufferedReader(new FileReader("E:\\buf_demo.txt"));
String str=null;
while((str=br.readLine())!=null){
bw.write(str);
//輸出換行符
bw.newLine();
//刷新緩衝輸出流緩存
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(bw!=null)
try {
//關閉流
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
if(br!=null)
try {
//關閉流
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.自定義一個簡單的緩衝區Reader類
示例代碼:
import java.io.FileReader;
import java.io.IOException;
public class MyReader {
private FileReader fr;//字符流,用於數據的讀取
//構造方法
public MyReader(FileReader fr){
this.fr=fr;
}
//讀取整行數據的自定義方法
public String MyReadLine() throws IOException{
//實例化一個StringBuilder對象用來臨時存儲數據
StringBuilder strBlr=new StringBuilder();
int ch=0;
while((ch=fr.read())!=-1){
//讀取到換行符時執行的操作
if(ch=='\r')
continue;
//讀取到換行符時執行的操作
if(ch=='\n')
return strBlr.toString();
else
strBlr.append((char)ch);
}
//當讀取的文件中僅有一行數據且沒有換行符時,返回讀取到的字符串
if(strBlr.length()!=0)
return strBlr.toString();
return null;
}
//關閉流的方法
public void close() throws IOException{
fr.close();
}
}
注意:以上的自定義類僅實現了緩衝流的兩個功能,可以利用裝飾設計模式將代碼優化。令該類繼承Reader接口,並且通過子類實現父類中的抽象方法。優化後的代碼如下。
示例代碼:
import java.io.FileReader;
import java.io.IOException;
public class MyReader {
private FileReader fr;//字符流,用於數據的讀取
//構造方法
public MyReader(FileReader fr){
this.fr=fr;
}
//讀取整行數據的自定義方法
public String MyReadLine() throws IOException{
//實例化一個StringBuilder對象用來臨時存儲數據
StringBuilder strBlr=new StringBuilder();
int ch=0;
while((ch=fr.read())!=-1){
//讀取到換行符時執行的操作
if(ch=='\r')
continue;
//讀取到換行符時執行的操作
if(ch=='\n')
return strBlr.toString();
else
strBlr.append((char)ch);
}
//當讀取的文件中僅有一行數據且沒有換行符時,返回讀取到的字符串
if(strBlr.length()!=0)
return strBlr.toString();
return null;
}
//關閉流的方法
public void close() throws IOException{
fr.close();
}
}
5.LineNumberReader
LineNumberReader
是跟蹤行號的緩衝字符輸入流。
構造方法:
LineNumberReader(Reader in)
使用默認輸入緩衝區的大小創建新的行編號 reader。
LineNumberReader(Reader in, int sz)
創建新的行編號 reader,將字符讀入給定大小的緩衝區。
常用方法:
int getLineNumber()
獲得當前行號。
void setLineNumber(int lineNumber)
設置當前行號。
int read()
讀取單個字符。
int read(char[] cbuf, int off, int len)
將字符讀入數組中的某一部分。
String readLine()
讀取文本行。
long skip(long n)
跳過字符。
void reset()
將該流重新設置爲最新的標記。
說明:LineNumberReader是基於Reader類,通過裝飾設計模式的一個裝飾類
示例代碼:
//部分代碼
public static void main(String[] args) {
LineNumberReader lnr=null;
try {
//實例化LineNumberReader對象
lnr=new LineNumberReader(new FileReader("G:\\line_test.txt"));
String str=null;
while((str=lnr.readLine())!=null){
//獲取行號
int num=lnr.getLineNumber();
if(num==6)
lnr.setLineNumber(7);
System.out.println(num+" "+str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(lnr!=null)
try {
lnr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
程序運行結果:
1 test:這是用於測試LineNumberReader的文件
2 LineNumberReader可以輸出數據的行號
3 就像你現在看到的這樣
4 麼麼噠
5 而且還可以設置行號
6 就像這樣
8 我其實是第七行,不是第八行
相關閱讀: