Java GBK中文亂碼問題分析

在io相關的操做中常常會出現亂碼問題html

 

好比在一個txt文件中按GBK編碼保存內容"淘!我喜歡!"java

而後用RandomAccessFile類讀取並打印一行。後端

RandomAccessFile raf = new RandomAccessFile("D:\\1.txt","r");
System.out.print(raf.readLine());

 

打印結果顯示亂碼:數組

 

在網上查詢到加入相關編碼解碼操做後能夠解決該問題數據結構

RandomAccessFile raf = new RandomAccessFile("D:\\1.txt","r");
System.out.print(new String(raf.readLine().getBytes("ISO-8859-1"),"gbk"));

 

 

問題:app

在這個過程當中發生了什麼?dom

 

要解答這個問題首先要知道編碼和解碼的概念以及產生的緣由:編輯器

爲何要編碼編碼

 

不知道你們有沒有想過一個問題,那就是爲何要編碼?咱們能不能不編碼?要回答這個問題必需要回到計算機是如何表示咱們人類可以理解的符號的,這些符號也就是咱們人類使用的語言。因爲人類的語言有太多,於是表示這些語言的符號太多,沒法用計算機中一個基本的存儲單元—— byte 來表示,於是必需要通過拆分或一些翻譯工做,才能讓計算機能理解。咱們能夠把計算機可以理解的語言假定爲英語,其它語言要可以在計算機中使用必須通過一次 翻譯,把它翻譯成英語。這個翻譯的過程就是編碼。因此能夠想象只要不是說英語的國家要可以使用計算機就必需要通過編碼。這看起來有些霸道,可是這就是現 狀,這也和咱們國家如今在大力推廣漢語同樣,但願其它國家都會說漢語,之後其它的語言都翻譯成漢語,咱們能夠把計算機中存儲信息的最小單位改爲漢字,這樣 咱們就不存在編碼問題了。spa

 

因此總的來講,編碼的緣由能夠總結爲:

    1.計算機中存儲信息的最小單元是一個字節即 8 個 bit,因此能表示的字符範圍是 0~255 個。

    2.人類要表示的符號太多,沒法用一個字節來徹底表示。

    3.要解決這個矛盾必須須要一個新的數據結構 char,從 char 到 byte 必須編碼。

名詞解釋:

解碼:將byte數組轉爲char數組。

編碼:將char數組轉爲byte數組。

 

計算機存儲的基本單位是byte,但打開一個文件時文件編輯器已經作了解碼的工做。

如下爲解碼過程描述

文件實際存儲的內容是(如下爲16進制):

打開文件後看到的內容爲

須要詳細說明如下代碼的處理過程

RandomAccessFile raf= new RandomAccessFile("D:\\1.txt","r");
System.out.print(raf.readLine());

 

首先看一下java.io.RandomAccessFile#readLine方法的源碼

public final String readLine() throws IOException {
        StringBuffer input = new StringBuffer();
        int c = -1;
        boolean eol = false;
        while (!eol) {
            switch (c = read()) {
            case -1:
            case '\n':
                eol = true;
                break;
            case '\r':
                eol = true;
                long cur = getFilePointer();
                if ((read()) != '\n') {
                    seek(cur);
                }
                break;
            default:
                input.append((char)c);
                break;
            }
        }
        if ((c == -1) && (input.length() == 0)) {
            return null;
        }
        return input.toString();
    }

 

主要關注read()部分和(char)c,read()是一個本地方法,做用是從文件中讀取一個byte字節。

(char)c是將變量c從byte類型轉換爲char類型,這是一個解碼操做。

問題:此處是以什麼格式進行解碼?

解碼格式是ISO-8859-1

raf.readLine()的處理過程以下

那麼

new String(raf.readLine().getBytes("ISO-8859-1"),"gbk")

 

這行代碼作了什麼

首先readLine()按行一字節一字節地讀取文件中的數據,而且按ISO-8859-1進行解碼拼成char數組,而後getBytes("ISO-8859-1")對拼成後的char數組按ISO-8859-1進行編碼獲取byte數組,最後new String(string,"gbk")對編碼後的byte數組用gbk格式進行解碼成char數組。

 

參考資料:深刻分析 Java 中的中文編碼問題

 

遺留問題:

一、如何避免重複轉碼。

二、RandomAccessFile的readLine()效率很是低,如何提升效率。

 

 

JAVA後端qq交流羣:477318923

相關文章
相關標籤/搜索