一、字符流的由來
由于使用位元組流操控中文時不是很方便,Java就提供了字符流來進行操控中文
實作原理:位元組流+編碼表
為什么用位元組流進行復制帶有中文的文本檔案時沒有問題?
因為底層操作會自動進行位元組拼接成中文
怎樣識別該位元組是中文呢?
漢字在存盤時,無論是UTF-8還是GBK,第一個位元組都是負數用來提示
二、編碼表
字符集:
是一個系統支持的所有字符的集合,包括國家文字、標點符號、圖形符號、數字等
計算機要準確的存盤和識別各種字符集符號,就需要進行字符編碼,一套字符集必然至少有一套字符編碼
常見的字符集有ASCII字符集、GBXXX字符集、Unicode字符集等
GBK:最常用的中文碼表,是在GB2312標準基礎上的擴展規范,使用了雙位元組編碼方案,共收錄了21003個漢字,完全兼容GB2312標準,同時支持繁體漢字以及日韓漢字等
GB18030:最新的中文碼表,收錄漢字70244個,采用多位元組編碼,每個字可以由1個、2個或4個位元組組成,支持中國少數民族的文字,同時支持繁體漢字以及日韓漢字等
Unicode字符集:
為了表達任意語言的任意字符而設計,是業界的一個標準,也稱為統一碼、標準萬國碼;它最多使用4個位元組的數字來表達每個字母、符號,或者文字,有三種編碼方案:UTF-8、UTF-16、UTF32,最常用的是UTF-8
UTF-8:可以用來表示Unicode標準中的任意字符,它是電子郵件、網頁及其他存盤或傳送檔案的應用中,優先采用的編碼,互聯網作業小組要求所有的互聯網協議都必須支持UTF-8編碼格式,它使用一至四個位元組為每個字符編碼
UTF-8編碼規則:
128個US-ASCII字符,只需要一個位元組編碼
拉丁文等字符,需要兩個位元組編碼
大部分常用字(含中文),使用三個位元組編碼
其他極少使用的UniCode輔助字符,使用四個位元組編碼
總結:編碼時使用那種規則,解碼就需要采用對應的規則,否則會亂碼
三、字串中的編碼解碼問題
編碼方法(IDEA):
byte[] getBytes():使用平臺默認的字符集將該String編碼為一系列位元組,將結果存盤到新的位元組陣列中
byte[] getBytes(String charsetName):使用指定的字符集將該String編碼為一系列位元組,將結果存盤到新的位元組陣列中
解碼方法(IDEA):
String(byte[]bytes):通過使用平臺的默認字符集解碼指定的位元組陣列來構造新的String
String(byte[]bytes,String charsetName):通過指定的字符集解碼指定的位元組陣列來構造新的String
IDEA中默認的編碼格式是UTF-8
四、字符流的編碼解碼問題
字符流抽象基類:
Reader:字符輸入流的抽象類
Writer:字符輸出流的抽象類
字符流中和編碼解碼問題相關的兩個類:
InputStreamReader:是從位元組流到字符流的橋梁:它讀取位元組,并使用指定的字符集將其解碼為字符,它使用的字符集可以由名稱指定,也可以被明確指定,或者可以接受平臺的默認字符集
構造方法:
InputStreamReader(InputStream in) | 創建一個使用默認字符集的InputStreamReader, |
|---|---|
InputStreamReader(InputStream in, String charsetName) |
創建一個使用命名字符集的InputStreamReader, |
OutputStreamWruter:是從字符流到位元組流的橋梁:使用自訂的字符集將寫入的字符編碼為位元組,它使用的字符集可以由名稱指定,也可以被明確指定,或者可以接受平臺的默認字符集
構造方法:
| OutputStreamWriter(OutputStream out) | 創建一個使用默認字符編碼的OutputStreamWriter, |
|---|---|
| OutputStreamWriter(OutputStream out, String charsetName) | 創建一個使用命名字符集的OutputStreamWriter, |
public class ConversionStreamDemo {
public static void main(String[] args) throws IOException {
//創建一個默認編碼格式的InputStreamReader\OutputStreamWriter
InputStreamReader ipsr = new InputStreamReader(new FileInputStream("E:\\abc.txt"));
OutputStreamWriter opsw = new OutputStreamWriter(new FileOutputStream("E:\\abc.txt"));
//寫入資料
opsw.write("你好啊");
opsw.close();
//讀資料,方式一:一次讀取一個位元組資料
int ch;
while ((ch = ipsr.read()) != -1) {
System.out.print((char) ch);
}
ipsr.close();
?
}
}
?
四、字符流寫資料的五種方法
| 方法名 | 說明 |
|---|---|
| void write(int c) | 寫一個字符 |
| void write(char[] cbuf) | 寫入一個字符陣列 |
| void write(char[] cbuf,int off,int len) | 寫入字符陣列的一部分 |
| void write(String str) | 寫入一個字串 |
| void write(String str,int off,int len) | 寫入一個字串的一部分 |
字符流寫資料需要注意緩沖區的問題,如果想要將緩沖區的資料加載出來需要在寫入方法后加上重繪方法flush();
前三個方法與位元組流寫入方法使用相同,這里重點介紹下面兩種方式
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
//創建一個默認編碼格式的OutputStreamWriter物件
OutputStreamWriter opsw=new OutputStreamWriter(new FileOutputStream("E:\\abc.txt"));
//方式一:寫入一個位元組
opsw.write(97);
opsw.flush();//如果需要在檔案中立即顯示輸入的資料,就需要加入重繪方法
//方式二:寫入一個字符陣列
char[]ch={'a','b','c','二'};
opsw.write(ch);
opsw.flush();//如果需要在檔案中立即顯示輸入的資料,就需要加入重繪方法
//方式三:寫入一個字符陣列的一部分
opsw.write(ch,0,2);
opsw.flush();//如果需要在檔案中立即顯示輸入的資料,就需要加入重繪方法
//方式四:寫入一個字串
opsw.write("一二三");
opsw.flush();//如果需要在檔案中立即顯示輸入的資料,就需要加入重繪方法
//方式五:寫入一個字串的一部分
opsw.write("三四五",1,2);
opsw.flush();//如果需要在檔案中立即顯示輸入的資料,就需要加入重繪方法
}
}
五、字符流讀資料的兩種方法
| 方法名 | 說明 |
|---|---|
| int read() | 一次讀取一個字符資料 |
| int read(char[] cbuf) | 一次讀取一個字符陣列資料 |
public class InputStreamReadDemo {
public static void main(String[] args) throws IOException {
//創建一個默認編碼格式的InputStreamReader
InputStreamReader ipsr=new InputStreamReader(new FileInputStream("E:\\abc.txt"));
//讀取資料,方式一一次讀取一個字符資料
int ch;
while ((ch=ipsr.read())!=-1){
System.out.print((char) ch);
}
ipsr.close();
//方式二:一次讀取一個字符陣列資料
char []ch=new char[1024];
int len;
while ((len=ipsr.read(ch))!=-1){
System.out.print(new String(ch,0,len));
}
ipsr.close();
}
}
?
小結:如果使用默認編碼格式的話,那么字符輸入流InputStreamReader可以使用子類FileReader來替代,字符輸出流OutputStreamWriter可以使用其子類FileWriter來替代,兩者在使用默認編碼格式的情況下作用一致,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/457526.html
標籤:Java
上一篇:檔案輸入/輸出流
