當使用字節流讀取文本文件時,可能會有一個小問題。就是遇到中文字符時,可能不會顯示完整的字符,那是因爲一箇中文字符可能佔用多個字節存儲。所以Java提供一些字符流類,以字符爲單位讀寫數據,專門用於處理文本文件。
1.符輸入流【Reader】
java.io.Reader
抽象類是表示用於讀取字符流的所有類的超類,可以讀取字符信息到內存中。它定義了字符輸入流的基本共性功能方法。
public void close()
:關閉此流並釋放與此流相關聯的任何系統資源。public int read()
: 從輸入流讀取一個字符。public int read(char[] cbuf)
: 從輸入流中讀取一些字符,並將它們存儲到字符數組 cbuf中 。
2.FileReader類
java.io.FileReader
類是讀取字符文件的便利類。構造時使用系統默認的字符編碼和默認字節緩衝區。
小貼士:
字符編碼:字節與字符的對應規則。Windows系統的中文編碼默認是GBK編碼表。
idea中UTF-8
字節緩衝區:一個字節數組,用來臨時存儲字節數據。
構造方法
FileReader(File file)
: 創建一個新的 FileReader ,給定要讀取的File對象。FileReader(String fileName)
: 創建一個新的 FileReader ,給定要讀取的文件的名稱。
當你創建一個流對象時,必須傳入一個文件路徑。類似於FileInputStream 。
- 構造舉例,代碼如下:
public class FileReaderConstructor throws IOException{
public static void main(String[] args) {
// 使用File對象創建流對象
File file = new File("a.txt");
FileReader fr = new FileReader(file);
// 使用文件名稱創建流對象
FileReader fr = new FileReader("b.txt");
}
}
讀取字符數據
- 讀取字符:
read
方法,每次可以讀取一個字符的數據,提升爲int類型,讀取到文件末尾,返回-1
,循環讀取,代碼使用演示:
public class FRRead {
public static void main(String[] args) throws IOException {
// 使用文件名稱創建流對象
FileReader fr = new FileReader("read.txt");
// 定義變量,保存數據
int b;
// 循環讀取
while ((b = fr.read())!=-1) {
System.out.println((char)b);
}
// 關閉資源
fr.close();
}
}
輸出結果:
我
是
一
個
好
男
人
!
小貼士:雖然讀取了一個字符,但是會自動提升爲int類型。
- 使用字符數組讀取:
read(char[] cbuf)
,每次讀取b的長度個字符到數組中,返回讀取到的有效字符個數,讀取到末尾時,返回-1
,代碼使用演示:
public class FRRead {
public static void main(String[] args) throws IOException {
// 使用文件名稱創建流對象
FileReader fr = new FileReader("read.txt");
// 定義變量,保存有效字符個數
int len;
// 定義字符數組,作爲裝字符數據的容器
char[] cbuf = new char[2];
// 循環讀取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(new String(cbuf));
}
// 關閉資源
fr.close();
}
}
輸出結果:
我是
一個
好男
人!
獲取有效的字符改進,代碼使用演示:
public class FISRead {
public static void main(String[] args) throws IOException {
// 使用文件名稱創建流對象
FileReader fr = new FileReader("read.txt");
// 定義變量,保存有效字符個數
int len ;
// 定義字符數組,作爲裝字符數據的容器
char[] cbuf = new char[2];
// 循環讀取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(new String(cbuf,0,len));
}
// 關閉資源
fr.close();
}
}
輸出結果:
我是
一個
好男
人!
3.字符輸出流【Writer】
java.io.Writer
抽象類是表示用於寫出字符流的所有類的超類,將指定的字符信息寫出到目的地。它定義了字節輸出流的基本共性功能方法。
void write(int c)
寫入單個字符。void write(char[] cbuf)
寫入字符數組。abstract void write(char[] cbuf, int off, int len)
寫入字符數組的某一部分,off數組的開始索引,len寫的字符個數。void write(String str)
寫入字符串。void write(String str, int off, int len)
寫入字符串的某一部分,off字符串的開始索引,len寫的字符個數。void flush()
刷新該流的緩衝。void close()
關閉此流,但要先刷新它。
4.FileWriter類
java.io.FileWriter
類是寫出字符到文件的便利類。構造時使用系統默認的字符編碼和默認字節緩衝區。
構造方法
FileWriter(File file)
: 創建一個新的 FileWriter,給定要讀取的File對象。FileWriter(String fileName)
: 創建一個新的 FileWriter,給定要讀取的文件的名稱。
當你創建一個流對象時,必須傳入一個文件路徑,類似於FileOutputStream。
- 構造舉例,代碼如下:
public class FileWriterConstructor {
public static void main(String[] args) throws IOException {
// 使用File對象創建流對象
File file = new File("a.txt");
FileWriter fw = new FileWriter(file);
// 使用文件名稱創建流對象
FileWriter fw = new FileWriter("b.txt");
}
}
基本寫出數據
寫出字符:write(int b)
方法,每次可以寫出一個字符數據,代碼使用演示:
public class FWWrite {
public static void main(String[] args) throws IOException {
// 使用文件名稱創建流對象
FileWriter fw = new FileWriter("fw.txt");
// 寫出數據
fw.write(97); // 寫出第1個字符
fw.write('b'); // 寫出第2個字符
fw.write('C'); // 寫出第3個字符
fw.write(30000); // 寫出第4個字符,中文編碼表中30000對應一個漢字。
/*
【注意】關閉資源時,與FileOutputStream不同。
如果不關閉,數據只是保存到緩衝區,並未保存到文件。
*/
// fw.close();
}
}
輸出結果:
abC田
小貼士:
- 未調用close方法,數據只是保存到了緩衝區,並未寫出到文件中。
關閉和刷新
因爲內置緩衝區的原因,如果不關閉輸出流,無法寫出字符到文件中。但是關閉的流對象,是無法繼續寫出數據的。如果我們既想寫出數據,又想繼續使用流,就需要flush
方法了。
flush
:刷新緩衝區,流對象可以繼續使用。close
:先刷新緩衝區,然後通知系統釋放資源。流對象不可以再被使用了。
代碼使用演示:
public class FWWrite {
public static void main(String[] args) throws IOException {
// 使用文件名稱創建流對象
FileWriter fw = new FileWriter("fw.txt");
// 寫出數據,通過flush
fw.write('刷'); // 寫出第1個字符
fw.flush();
fw.write('新'); // 繼續寫出第2個字符,寫出成功
fw.flush();
// 寫出數據,通過close
fw.write('關'); // 寫出第1個字符
fw.close();
fw.write('閉'); // 繼續寫出第2個字符,【報錯】java.io.IOException: Stream closed
fw.close();
}
}
小貼士:即便是flush方法寫出了數據,操作的最後還是要調用close方法,釋放系統資源。
寫出其他數據
- 寫出字符數組 :
write(char[] cbuf)
和write(char[] cbuf, int off, int len)
,每次可以寫出字符數組中的數據,用法類似FileOutputStream,代碼使用演示:
public class FWWrite {
public static void main(String[] args) throws IOException {
// 使用文件名稱創建流對象
FileWriter fw = new FileWriter("fw.txt");
// 字符串轉換爲字節數組
char[] chars = "我和我的祖國一刻也不能分割".toCharArray();
// 寫出字符數組
//fw.write(chars); // 我和我的祖國一刻也不能分割
// 寫出從索引2開始,2個字節。
fw.write(chars,2,2); // 我的
// 關閉資源
fw.close();
}
}
- 寫出字符串:
write(String str)
和write(String str, int off, int len)
,每次可以寫出字符串中的數據,更爲方便,代碼使用演示:
public class FWWrite {
public static void main(String[] args) throws IOException {
// 使用文件名稱創建流對象
FileWriter fw = new FileWriter("fw.txt");
// 字符串
String msg = "我和我的祖國一刻也不能分割";
// 寫出字符數組
//fw.write(msg); //我和我的祖國一刻也不能分割
// 寫出從索引2開始,2個字節。
fw.write(msg,2,2); // 我的
// 關閉資源
fw.close();
}
}
- 續寫和換行:操作類似於FileOutputStream。
public class FWWrite {
public static void main(String[] args) throws IOException {
// 使用文件名稱創建流對象,可以續寫數據
FileWriter fw = new FileWriter("fw.txt",true);
// 寫出字符串
fw.write("我是");
// 寫出換行
fw.write("\r\n");
// 寫出字符串
fw.write("好男人");
// 關閉資源
fw.close();
}
}
輸出結果:
我是
好男人
小貼士:字符流,只能操作文本文件,不能操作圖片,視頻等非文本文件。
當我們單純讀或者寫文本文件時 使用字符流 其他情況使用字節流