要對Java Web項目進行編碼原因:
1、在計算機中存儲信息的最小單位是1個字節,即8個bit,所以能表示的字符范圍是0~255個。
2、電腦需要表示的符號太多、無法用1個字節完全表示。
要解決這個問題,必須要有一個新的數據結構char,而從bit到char就要進行編碼。
常見的編碼格式:
1、ASCII碼
總共128個,用1個字符的低7位表示,0~31是控制字符,如換行、回車、刪除等。32~126是打印字符,可以通過鍵盤輸入並且表示出來
2、ISO-8859-1
ISO組織在ASCII的基礎上又制定了一系列標准來就、擴展ASCII編碼,他們是ISO-8859-1和ISO-8859-15。其中前者涵蓋了大多數西歐語言字符,所以運用得比較廣泛。ISO-8859-1仍然是單字節編碼,它總共能表示256個字符.
因為ISO-8859-1是單字節的,所以很多中文字符(兩個字節)在編碼時用ISO-8859-1表示時,因超出表示范圍,所以出現??很多情況是將中文字符用ISO-8859-1表示。我們稱之為“黑洞”(它會將不認識的字符吸收掉)。
由於現在大部分基礎的Java框架或系統默認的字符集編碼都是ISO-8859-1,所以很容易出現亂碼問題。
3、GB2312
GB2312是雙字節編碼,總的編碼范圍是A1-F7,其中A1-A9是符號區,總共有682個符號,B0-F7是漢字區,包含6763個漢字。
4、GBK
GBK全稱是 漢字內碼擴展規范,是中國國家技術監督局開發出來擴展GB2312,並加入了更多的漢字,它的編碼范圍是8140~FEFE,能表示21003個漢字。它與GB2312是兼容的。
5、GB18030
Gb18030全稱是 信息技術中文編碼字符集,是我國的強制標准,它可能是單字節的、雙字節或者是四字節編碼。它的編碼與GB2312編碼兼容。
6、UTF-16
ISO試圖創建一個全新的超語言字典,世界上的語言都能使用這個字典進行翻譯。UTF-16具體定義了Unicode字符在計算機中的存取方法,UTF-16用兩個字節來表示Unicode的轉化格式,它采用定長的表示方法,即無論什麼字符都可以用兩個字節表示。兩個字節就是16個bit,所以叫做UTF-16。Java以UTF-16作為內存中字符存儲格式。
7、UTF-8
UTF-8采用變長的方法,克服了UTF-16中定長的浪費資源的缺點。每個編碼區域都有自己不用的字碼長度,不同類型的字符可以由1~6個字節組成。
UTF-8對單字節范圍內的字符仍然用1個字節表示,對漢字采用3個字節表示。
UTF-8的編碼規則:當是1個字節的時候,最高位為0,則表示這是一個ASCII字符,由此可見,所有ASCII編碼已經是UTF-8.
當是1個字節,以11開頭,則連續的1的個數暗示這個字符的字節數,如110XXXXX表示它是雙字節UTF-8字符的首字節。
當是1個字節,以10開頭,表示它不是首字節。則需要向前查找才能得到它的首字節。
上述幾種編碼格式的比較:
GBK能處理所有的漢字字符,所以將GB2312和GBK進行比較時,應該選擇GBK。
UTF-8與UTF-16都是處理Unicode編碼,盡管他們的編碼格式不相同,但相對來說,UTF-16的編碼效率較高,從字符到字節的轉換更簡單,進行字符串操作也更好,適合磁盤和內存之間使用,所以Java的內存編碼采用UTF-16來編碼。但是在網絡傳輸的時候,應使用UTF-8,因為網絡傳輸比較容易損壞字節流,而UTF-8對ASCII字符采用了單字節編碼,另外單個字節損壞不會影響到後面的其他字符,在編碼效率中介於GBK和UTF-16之間,所以,UTF-8在編碼效率和編碼安全性方面都做了平衡,是理想的中文編碼方式。
在Java中需要編碼的場景:涉及到字符到字節或者字節到字符的轉換上。分為下面兩類:
在I/O操作中存在的編碼
在內存操作中的編碼
在Java中編解碼,如
String name = "today 天氣真好";
byte[] iso8859 = name.getBytes("ISO-8859-1");
byte[] gb2312 =name.getBytes("GB2312");
將字符串按照相應的編碼格式進行編碼,轉換為byte數組。
String。getBytes(charsetName)編碼過程:根據charsetName找到Charset類,然後根據這個字符集編碼生成CharserEncoder,這個類是所有字符編碼的父類,針對不同的字符編碼集在其子類中定義了如何實現編碼,有了CharserEncode對象後就可以條用encode方法實現編碼了。
常見問題分析
1、中文變成了看不懂的字符
字符串在解碼時所用的字符集和編碼的時候所用的字符集不一致時就會導致漢字變成看不懂的亂碼,而且是一個漢字字符變成兩個亂碼字符。
2、一個漢字變成一個問號
將中文和中文符號經過不支持中文的IDO-8859-1編碼後,所有字符變成了“?”。這是因為ISO-8859-1在編解碼的時候,遇到不在碼值范圍內字符會統一用3f表示,這也就是“黑洞”。而ISO-8859-1不認識的字符變成了“?”。
3、一個漢字變成兩個問號
中文經過多次編碼,但是其中有一次編碼或者解碼不對而出現以上情況。
4、一種不正常的正確編碼
有時候我們會發現,當你在Jsp頁面獲取到參數時,String value = request.getParameter("name");會出現亂碼。而使用 String value = String(request.getParameter("name".getBytes("ISO-8859-1"),"GBK"));時就能正常顯示中文。
事實上是這樣子的,ISO-8859-1字符集的編碼范圍是0000~00FF,正好和一個字節的編碼范圍相對應。這種特性保證了使用ISO-8859-1進行編碼和解碼時編碼數值不變。雖然中文字符在網絡傳輸的過程中,被錯誤地拆分為兩個歐洲字符,但由於輸出的時候也使用了ISO-8859-1,結果被拆開的中文字又被合並,剛好組成了一個正確的漢字。缺點是增加多一次編碼。
徹底解決該問題的方法是,在Tomcat的配置文件中將useBodyEncodingURI配置項設置為“true”。
網站國際化:
將網站的文字轉換語言形式。首先要將網站的編碼格式設置為支持多種語言的UTF-8編碼,然後對頁面進行本地化翻譯工作。本地化翻譯分為:機器自動翻譯,類似於Google翻譯或者是Office繁簡轉換;人工翻譯,代價較高。前者技術難度高,且有些語義難以准確翻譯。後一種系統維護麻煩。
例子:由繁到簡過程:由人工翻譯將簡體中文的GBK編碼漢字轉換為繁體的Big5編碼漢字,形成一個碼表。由於漢字字符的字節特性,在兩個連續的字節的最高位都大於1時,用這兩個連續的字節組合起來從碼表中查找,進行對照翻譯。這個查找和翻譯的工作在前端的Web服務器上動態完成,自動將後台輸出的簡體中文轉換為繁體中文。但是也存在有些詞組翻譯不好,很難解決跨語言問題。