posts - 262,  comments - 221,  trackbacks - 0

          Unicode中文“藝”字: 827A

          二進制的“藝”字編碼:1000 0010 0111 1010

          UTF-8的中文編碼規則: 1110xxxx 10xxxxxx 10xxxxxx

          UTF-8的“藝”字編碼: 1110【1000】 10【0010】【01】 10【11】【1010】

          UTF-8的轉碼過程解析: 8對應的1000被填入第一字節剩余的4位。2對應的0010被填入第2字節剩余的前4位。7對應的0111被拆開,前2位01被填入第2字節的后兩位,后2位1被填入第3字節的前2位。A對應的1010被填入第3字節的后4位。

          UTF-8的最終編碼結果:11101000---對應E8;10001001---對應89;10111010---對應BA。所以最終的UTF-8編碼就是%E8%89%BA

          Unicode到UTF-8的轉換:Unicode的16進制編碼<-->對應的2進制編碼<-->UTF-8規范的2進制編碼<-->UTF-8規范的16進制編碼

          也就是說假如在Java的底層JVM,由于采用的是Unicode編碼字符集,對“藝”字的編碼是827A。那么在網絡傳輸的過程中,我們當然不能直接傳輸827A這個字符過去代表藝”這個漢字,而必須要轉換成0,1這樣的字節流,才能在網絡中傳輸。

          所以說UTF-8是一種為了方便網路傳輸,節省傳輸數量,而對Unicode的字符集的字符編號進行轉換,從定長的2個字節(16進制)轉換成1~3個的變長字節(2進制)表示的轉換格式。

          由于Unicode采用的是2個字節的編碼方式,而UTF-8轉換后可能是1~3個字節,所以同一個漢字,在Unicode中的編碼和經UTF-8轉換后的編碼值肯定是不同的。就好像藝字的Unicode編碼是827A,經轉換后的3個字節是E889BA。

          所以說對于英文字符來說,采用UTF-8對Unicode編碼轉換后節省了一倍的傳輸成本(由定長的2個字節變長1個字節),但對于原本雙字節的東亞字符來說,反而增加了成本,是原來的1.5倍。

          小結:

          ①ASCII、GB2312、GBK、GB18030、Big5、Unicode都是字符集的名稱。它們定義了采用1~2個字節的編碼規范,為每個字符賦予了一個獨一無二的編號。這個編號就是我們所說的“字符編碼”。

          ②Unicode字符集定義的字符編碼并不適合直接通過網絡傳輸表達,因為它們必須轉換成像0101這樣的二進制字節流傳輸。所以就出現了不同的轉換規范實現方式:UTF-8,TF-16等。這些不同的轉換規范轉換后的編碼值和Unicode是不同的。

          對于UTF-8來說,它采用變長字節表示所有Unicode字符,對于英文來說和ASCII兼容,對于東亞字符來說,是原來傳輸成本的1.5倍。所以采用UTF-8編碼轉換方式雖然有利于統一,但增加了中文等雙字節字符的傳輸成本。

          UTF-8采用首字節的高位"1"的個數表示字符的編碼長度。例如在Unicode的編碼規范中:漢字的表示區間為U-00000800至U-0000FFFF對應的UTF-8的轉換規則為:1110xxxx 10xxxxxx 10xxxxxx 首字節3個1代表這個字符的編碼長度為3個字節。如果是2個1則表示2個字節

          ③在底層的平臺中如JVM,采用的是Unicode字符集,當要把這些字符通過網絡傳輸時,可以選擇通過UTF-8或其他(例如GB2312)編碼轉換方式對要傳輸的字符編碼進行轉換。如果目的端也是采用Unicode字符集,那么UTF-8轉換后的編碼可以被正常識別并解碼成最終對應的Unicode字符集編號。如果是非Unicode字符集平臺則可能出現亂碼(UTF-8中漢字的3個連續字節被解析成GB2312的2個連續字節,出現丟失)。所以推薦在傳輸的兩端采用Unicode字符集編碼,在傳輸方式上采用UTF-8轉換方式。

          javac命令是以系統默認編碼讀入源文件,然后按Unicode進行編碼的。(備注:每個文件都有自己的編碼,javac命令按照默認的文件編碼讀入,但是在將.java文件轉換成.class的過程中,javac會將所有的字符轉化成unicode的格式保存。)

          在運行時JVM也是采用unicode編碼的,并且默認輸入和輸出使用的都是操作系統的默認編碼。也就是說在new String(bytes[,encode])中,系統認為輸入的bytes是編碼為encode的字節流(如果不指定encode,那么就是默認使用系統的編碼方式),換句話說,如果按encode來翻譯bytes才能得到正確的原始字符,這個字符最后要在java中保存,它還是要從這個encode轉換成Unicode的。

          也就是說,假如我們需要從磁盤文件、數據庫記錄、網絡傳輸一些字符,保存到Java的變量中,要經歷由bytes-->encode字符-->Unicode字符的轉換(例如new String(bytes, encode));而要把Java變量保存到文件、數據庫或者通過網絡傳輸,系統要做一個Unicode字符-->encode字符-->bytes的轉換(例如String.getBytes([encode]))



          -------------------------------------------------------------
          生活就像打牌,不是要抓一手好牌,而是要盡力打好一手爛牌。
          posted on 2010-02-16 23:23 Paul Lin 閱讀(3691) 評論(3)  編輯  收藏 所屬分類: J2SE


          FeedBack:
          # re: 【Java基礎專題】編碼與亂碼(01)---編碼基礎
          2012-12-12 16:16 | 砂銀
          非常有用,謝謝  回復  更多評論
            
          # re: 【Java基礎專題】編碼與亂碼(01)---編碼基礎[未登錄]
          2014-04-22 11:08 | 小龍
          謝謝,幫了我大忙!  回復  更多評論
            
          # re: 【Java基礎專題】編碼與亂碼(01)---編碼基礎[未登錄]
          2016-04-04 14:16 |
          666666666666666666666這幾天正在做個類似工程編碼出現錯誤  回復  更多評論
            
          <2014年4月>
          303112345
          6789101112
          13141516171819
          20212223242526
          27282930123
          45678910

          常用鏈接

          留言簿(21)

          隨筆分類

          隨筆檔案

          BlogJava熱點博客

          好友博客

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 宝山区| 东安县| 西宁市| 香港| 本溪| 新营市| 清丰县| 合肥市| 丹江口市| 剑川县| 白朗县| 碌曲县| 博湖县| 马鞍山市| 泌阳县| 防城港市| 普定县| 察雅县| 慈利县| 呼图壁县| 甘肃省| 揭阳市| 宁波市| 临西县| 修文县| 鹿邑县| 赣榆县| 青海省| 新巴尔虎右旗| 广昌县| 禄丰县| 云林县| 阿拉善左旗| 诸城市| 措美县| 新疆| 永昌县| 秦安县| 且末县| 武山县| 沧源|