場景:
讀取一個大文本文件,並輸出到控制檯。java
在這裏咱們選擇使用nio進行讀取文本文件,在輸出的過程當中,有些文件中英文都顯示正常,有些則偶爾出現中文亂碼,經思考發現,在 ByteBuffer.allocate 時分配空間,若是中英混合的文件中就會出現中文字符只讀取了一部分的問題,若是文本爲等長編碼字符集的時候,能夠根據編碼集 byte 長度進行 allocate ,例如 GBK 爲2 byte ,因此咱們 allocate 時未2的倍數便可,但像 UTF-8 這類變長的編碼字符集時則沒那麼簡單了。dom
下面就是 UTF-8 的編碼方式編碼
0xxxxxxx 110xxxxx 10xxxxxx 1110xxxx 10xxxxxx 10xxxxxx 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
經過分析咱們發現,在讀取中咱們經過處理臨界值來解決 UTF-8 編碼字符讀取問題。code
示例代碼以下:
RandomAccessFile rf = new RandomAccessFile("zh.txt", "rw"); FileChannel channel = rf.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(4); // 至少爲4,由於UTF-8最大爲4字節 while (channel.read(buffer) != -1) { byte b; int idx; out : for (idx = buffer.position()-1; idx >= 0; idx--) { b = buffer.get(idx); if ((b & 0xff) >> 7 == 0) { // 0xxxxxxx break; } if ((b& 0xff & 0xc0) == 0xc0) { // 11xxxxxx,110xxxxx、1110xxxx、11110xxx idx -= 1; break; } if ((b & 0xff & 0x80) == 0x80) { for (int i = 1; i < 4; i++) { b = buffer.get(idx - i); if ((b & 0xff & 0xc0) == 0xc0) { if ((b & 0xff) >> (5 + 1 - i) == 0xf >> (3 - i)) { break out; } else { idx = idx - 1 - i; break out; } } } } } buffer.flip(); int limit = buffer.limit(); buffer.limit(idx+1); // 阻止讀取跨界數據 System.out.println(Charset.forName("UTF-8").decode(buffer).toString()); buffer.limit(limit); // 恢復limit buffer.compact(); } channel.close(); rf.close();