字符集
根據(jù) Sun 的文檔,一個 Charset 是“十六位 Unicode 字符序列與字節(jié)序列之間的一個命名的映射”。實(shí)際上,一個 Charset 允許您以盡可能最具可移植性的方式讀寫字符序列。
Java 語言被定義為基于 Unicode。然而在實(shí)際上,許多人編寫代碼時都假設(shè)一個字符在磁盤上或者在網(wǎng)絡(luò)流中用一個字節(jié)表示。這種假設(shè)在許多情況下成立,但是并不是在所有情況下都成立,而且隨著計算機(jī)變得對 Unicode 越來越友好,這個假設(shè)就日益變得不能成立了。
編碼/解碼
要讀和寫文本,我們要分別使用 CharsetDecoder 和 CharsetEncoder。將它們稱為 解碼器 和 編碼器 是有道理的。
一個 字符 不再表示一個特定的位模式,而是表示字符系統(tǒng)中的一個實(shí)體。因此,由某個實(shí)際的位模式表示的字符必須以某種特定的 編碼 來表示。
CharsetDecoder 用于將逐位表示的一串字符轉(zhuǎn)換為具體的 char 值。同樣,一個 CharsetEncoder 用于將字符轉(zhuǎn)換回位。
處理文本的正確方式
現(xiàn)在我們將分析這樣一個程序。這個程序非常簡單 ― 它從一個文件中讀取一些文本,并將該文本寫入另一個文件。但是它把該數(shù)據(jù)當(dāng)作文本數(shù)據(jù),并使用 CharBuffer 來將該數(shù)句讀入一個 CharsetDecoder 中。同樣,它使用 CharsetEncoder 來寫回該數(shù)據(jù)。
我們將假設(shè)字符以 GBK 字符集的形式儲存在磁盤上。盡管我們必須為使用 Unicode 做好準(zhǔn)備,但是也必須認(rèn)識到不同的文件是以不同的格式儲存的,而 ASCII 無疑是非常普遍的一種格式。事實(shí)上,每種 Java 實(shí)現(xiàn)都要求對以下字符編碼提供完全的支持:
- GBK
- GB2312
- US-ASCII
- ISO-8859-1
- UTF-8
- UTF-16BE
- UTF-16LE
- UTF-16
在打開相應(yīng)的文件、將輸入數(shù)據(jù)讀入名為 inputData 的 ByteBuffer 之后,我們的程序必須創(chuàng)建 GBK 字符集的一個實(shí)例:
Charset gbk = Charset.forName( "GBK" );
然后,創(chuàng)建一個解碼器(用于讀取)和一個編碼器 (用于寫入):
CharsetDecoder decoder = gbk.newDecoder();
CharsetEncoder encoder = gbk.newEncoder();
為了將字節(jié)數(shù)據(jù)解碼為一組字符,我們把 ByteBuffer 傳遞給 CharsetDecoder,結(jié)果得到一個 CharBuffer:
CharBuffer cb = decoder.decode( inputData );
如果想要處理字符,我們可以在程序的此處進(jìn)行。但是我們只想無改變地將它寫回,所以沒有什么要做的。
要寫回數(shù)據(jù),我們必須使用 CharsetEncoder 將它轉(zhuǎn)換回字節(jié):
ByteBuffer outputData = encoder.encode( cb );
在轉(zhuǎn)換完成之后,我們就可以將數(shù)據(jù)寫到文件中了。
場景描述:
我們要將一個GBK編碼的文件(gbk.txt)轉(zhuǎn)存到一個UTF編碼的文件(utf.txt)中。
- 我們的
gbk.txt文件是一個 ‘GBK’編碼保存的文件文件中有一段中文:

- 使用Charset 對GBK文件進(jìn)行GBK解碼,然后再進(jìn)行UTF編碼保存,代碼如下
@Test
public void charsetTest() {
try {
FileInputStream fin = new FileInputStream("/Users/dongsj/workspace/dsj/javaSpace/nettyDemo/src/test/resources/nio/gbk.txt");
FileChannel fileChannel = fin.getChannel();
ByteBuffer inputData = ByteBuffer.allocate(1024);
int result = fileChannel.read(inputData);
inputData.flip(); // !!!
System.out.println("Read result : " + result);
Charset gbk = Charset.forName("GBK");
Charset utf = Charset.forName("UTF-8");
CharsetDecoder gbkDecoder = gbk.newDecoder(); // gbk解碼器
//CharsetEncoder gbkEncoder = gbk.newEncoder(); // gbk編碼器
CharsetEncoder utfEncoder = utf.newEncoder(); // utf編碼器
CharBuffer charBuffer = gbkDecoder.decode(inputData);
//ByteBuffer outputBuffer = gbkEncoder.encode(charBuffer); // 使用gbk編碼
ByteBuffer outputBuffer = utfEncoder.encode(charBuffer); // 使用utf編碼
FileOutputStream fout = new FileOutputStream("/Users/dongsj/workspace/dsj/javaSpace/nettyDemo/src/test/resources/nio/utf.txt");
FileChannel channelout = fout.getChannel();
result = channelout.write(outputBuffer);
System.out.println("Write result : " + result);
} catch (CharacterCodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
- 結(jié)果


- 如果依然采用GBK編碼保存的話,結(jié)果一定是亂碼,畢竟是中文
