字符編碼和字符集
字符編碼
計算機中儲存的信息都是用二進制數表示的,而我們在屏幕上看到的數字、英文、標點符號、漢字等字符是二進制數轉換之后的結果。按照某種規則,將字符存儲到計算機中,稱為編碼。反之,將存儲在計算機中的二進制數按照某種規則解析顯示出來,稱為解碼。比如說,按照A規則存儲,同樣按照A規則解析,那么就能顯示正確的文本符號。反之,按照A規則存儲,再按照B規則解析,就會導致亂碼現象。
編碼:字符 --> 字節
解碼:字節 --> 字符
- 字符編碼,是一套自然語言的字符與二進制數之間的對應規則。
字符集
- 字符集,也叫編碼表,是一個系統支持的所有字符集合,包括國家文字、標點符號、圖形符號、數字等。
計算機要准確的存儲和識別各種字符集符號,需要進行字符編碼,一套字符集必然至少有一套字符編碼。常見字符集有ASCII字符集、GBK字符集、Unicode字符集等。
編碼引出的問題
在IDEA中,使用FileReader讀取項目中的文本文件。由於IDEA的設置,都是默認的UTF-8編碼,所以沒有任何問題。但是,當讀取系統中創建的文本文件時,由於系統的默認是GBK編碼,就會出現亂碼。
那么該如何解決呢?我們可以使用InputStreamReader類、OutputStreamWriter類,指定編碼來進行讀寫操作,這時候就不會出現亂碼的情況了。
OutputStreamWriter類
java.io.OutputStreamWriter是字符流通向字節流的橋梁:可使用指定的charset將要寫入流中的字符編碼成字節(編碼)。它使用的字符集可以由名稱指定或顯式給定,否則將接受平台默認的字符集。
OutputStreamWriter類是java.io.Writer的子類,所以可以使用父類方法:
public void write(int c)
// 寫入單個字符。
public void write(char cbuf[])
// 寫入字符數組。
abstract public void write(char cbuf[], int off, int len)
// 寫入字符數組的某一部分,off是數組的開始索引,len是寫的字符個數。
public void write(String str)
// 寫入字符串。
public void write(String str, int off, int len)
//寫入字符的某一部分。off是字符的開始素,len是寫的字符個數。
abstract public void flush()
// 刷新該流的緩沖。
abstract public void close()
// 關閉此流,但會先刷新它。
構造方法
OutputStreamWriter(OutputStream out)
// 創建使用默認編碼的OutputStreamWriter對象
OutputStreamWriter(OutputStream out, String charsetName)
// 創建使用指定編碼的OutputStreamWriter對象
參數:
OutputStreamWriter out:字節輸出流
String charsetName:指定編碼表的名稱,不區分大小寫。如utf-8/UTF-8。
使用步驟:
1.創建OutputStreamWriter對象,構造方法中傳遞字節輸出流和指定的編碼表名稱。
2.使用OutputStreamWriter對象中的方法write,把字符轉換為字節存儲到緩沖區中(編碼)。
3.使用OutputStreamWriter對象中的方法flush,把內存緩沖區中的字節刷新到文件中(使用字節流寫字節的過程)。
4.釋放資源。
舉例:指定編碼,將數據保存到文件中。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class DemoOutputStreamWriter {
public static void main(String[] args) throws IOException {
Gbk_TXT();
}
private static void Gbk_TXT() throws IOException {
// 創建OutputStreamWriter對象,構造方法中傳遞字節輸出流和指定的編碼表名稱。指定編碼為GBK。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo35/OutputStreamWriter.txt"), "gbk");
// 使用OutputStreamWriter對象中的方法write,把字符轉換為字節存儲到緩沖區中(編碼)。
for (int i = 0; i < 5; i++) {
osw.write("你好!" + i);
osw.write("\n");
}
// 使用OutputStreamWriter對象中的方法flush,把內存緩沖區中的字節刷新到文件中(使用字節流寫字節的過程)。
osw.flush();
// 釋放資源。
osw.close();
}
}
運行,生成一個OutputStreamWriter.txt文件,文件內容如下:
由於IDEA默認編碼是UTF-8,這里使用了GBK編碼格式寫入數據進文件,所以在IDEA里面查看文件的內容出現亂碼。
InputStreamReader類
java.io.InputStreamReader是字節流通向字符流的橋梁:它使用指定的charset讀取字節並將其解碼為字符(解碼)。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平台默認的字符集。
InputStreamReader類是java.io.Reader的子類,所以可以使用父類方法:
public void close()
// 關閉此流並釋放與此流相關聯的任何系統資源。
public int read()
// 從輸入流讀取一個字符。
public int read(char[] chars)
// 從輸入流中讀取一些字符,並將它們存儲到字符數組chars中。
構造方法
InputStreamReader(InputStream in)
// 創建默認字符集的InputStreamReader對象
InputStreamReader(InputStream in, String charsetName)
// 創建指定字符集的InputStreamReader對象
參數:
InputStream in:字符輸入流
String charsetName:指定編碼表的名稱,不區分大小寫。如gbk/GBK。
使用步驟:
1.創建InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱。
2.使用InputStreamReader對象中的方法read,讀取文件。
3.釋放資源。
注意事項:構造方法中指定的編碼表名稱要和文件的編碼相同,否則會發生亂碼。
舉例:按指定解碼格式,讀取OutputStreamWriter.txt文件的內容
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class DemoInputStreamReader {
public static void main(String[] args) throws IOException {
decode_GBK();
}
private static void decode_GBK() throws IOException {
// 創建InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱。
InputStreamReader isr = new InputStreamReader(new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo35/OutputStreamWriter.txt"), "GBK");
// 使用InputStreamReader對象中的方法read,讀取文件。
char[] chars = new char[25];
while ((isr.read(chars)) != -1) {
System.out.println(chars);
}
// 釋放資源。
isr.close();
}
}
控制台輸出:
你好!0
你好!1
你好!2
你好!3
你好!4
練習:轉換文件編碼
將編碼GBK編碼的文件文本,轉換為UTF-8編碼的文件文本。
分析:
1.創建InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱GBK。
2.創建OutputStreamWriter對象,構造方法中傳遞字節輸出流和指定的編碼表名稱UTF-8。
3.使用InputStreamReader對象中的方法read,讀取文件。
4.使用OutputStreamWriter對象中的方法write,把讀取的數據寫入到文件中。
5.釋放資源。
GBK.txt文件內容如下:
代碼實現:
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class DemoInOutAndReaderWriter {
public static void main(String[] args) throws IOException {
method();
}
private static void method() throws IOException {
// 創建InputStreamReader對象,構造方法中傳遞字節輸入流和指定的編碼表名稱GBK。
InputStreamReader isr = new InputStreamReader(new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo35/GBK.txt"), "GBK");
// 創建OutputStreamWriter對象,構造方法中傳遞字節輸出流和指定的編碼表名稱UTF-8。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo35/UTF_8.txt"), "UTF-8");
// 使用InputStreamReader對象中的方法read,讀取文件。
int len = 0;
while ((len = isr.read()) != -1) {
osw.write(len);
}
// 釋放資源。
isr.close();
osw.close();
}
}
運行生成一個UTF_8.txt文件,文件內容如下: