一、字元流的由來 由於使用位元組流操控中文時不是很方便,Java就提供了字元流來進行操控中文 實現原理:位元組流+編碼表 為什麼用位元組流進行複製帶有中文的文本文件時沒有問題? 因為底層操作會自動進行位元組拼接成中文 怎樣識別該位元組是中文呢? 漢字在存儲時,無論是UTF-8還是GBK,第一個位元組都是負數用來 ...
一、字元流的由來
由於使用位元組流操控中文時不是很方便,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();
}
}