日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

再谈java乱码:GBK和UTF-8互转尾部乱码问题分析

發布時間:2025/3/21 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 再谈java乱码:GBK和UTF-8互转尾部乱码问题分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一直以為java中任意unicode字符串可以使用任意字符集轉為byte[]再轉回來只要不拋出異常就不會丟失數據事實證明這是錯的。

經過這個實例也明白了為什么 getBytes()需要捕獲異常雖然有時候它也沒有捕獲到異常。

言歸正傳先看一個實例。

用ISO-8859-1中轉UTF-8數據

設想一個場景

用戶A有一個UTF-8編碼的字節流通過一個接口傳遞給用戶B

用戶B并不知道是什么字符集他用ISO-8859-1來接收保存

在一定的處理流程處理后把這個字節流交給用戶C或者交還給用戶A他們都知道這是UTF-8他們解碼得到的數據不會丟失。

下面代碼驗證

public static void main(String[] args) throws Exception {//這是一個unicode字符串與字符集無關String str1 = "用戶";System.out.println("unicode字符串"+str1);//將str轉為UTF-8字節流byte[] byteArray1=str1.getBytes("UTF-8");//這個很安全UTF-8不會造成數據丟失System.out.println(byteArray1.length);//打印6沒毛病//下面交給另外一個人他不知道這是UTF-8字節流因此他當做ISO-8859-1處理//將byteArray1當做一個普通的字節流按照ISO-8859-1解碼為一個unicode字符串String str2=new String(byteArray1,"ISO-8859-1");System.out.println("轉成ISO-8859-1會亂碼"+str2);//將ISO-8859-1編碼的unicode字符串轉回為byte[]byte[] byteArray2=str2.getBytes("ISO-8859-1");//不會丟失數據//將字節流重新交回給用戶A//重新用UTF-8解碼String str3=new String(byteArray2,"UTF-8");System.out.println("數據沒有丟失"+str3); }

輸出

unicode字符串用戶 6 轉成ISO-8859-1會亂碼?”¨??· 數據沒有丟失用戶

用GBK中轉UTF-8數據

重復前面的流程將ISO-8859-1 用GBK替換。

只把中間一段改掉

//將byteArray1當做一個普通的字節流按照GBK解碼為一個unicode字符串String str2=new String(byteArray1,"GBK");System.out.println("轉成GBK會亂碼"+str2);//將GBK編碼的unicode字符串轉回為byte[]byte[] byteArray2=str2.getBytes("GBK");//數據會不會丟失呢

運行結果

unicode字符串用戶 6 轉成GBK會亂碼鐢ㄦ埛 數據沒有丟失用戶

好像沒有問題這就是一個誤區。

修改原文字符串重新測試

將兩個漢字 “用戶” 修改為三個漢字 “用戶名” 重新測試。

ISO-8859-1測試結果

unicode字符串用戶名 9 轉成GBK會亂碼?”¨??·? 數據沒有丟失用戶名

GBK 測試結果

unicode字符串用戶名 9 轉成GBK會亂碼鐢ㄦ埛鍚 數據沒有丟失用戶?

結論出來了

ISO-8859-1 可以作為中間編碼不會導致數據丟失

GBK 如果漢字數量為偶數不會丟失數據如果漢字數量為奇數必定會丟失數據。

why

為什么奇數個漢字GBK會出錯

直接對比兩種字符集和奇偶字數的情形

重新封裝一下前面的邏輯寫一段代碼來分析

public static void demo(String str) throws Exception {System.out.println("原文" + str);byte[] utfByte = str.getBytes("UTF-8");System.out.print("utf Byte");printHex(utfByte);String gbk = new String(utfByte, "GBK");//這里實際上把數據破壞了System.out.println("to GBK" + gbk);byte[] gbkByte=gbk.getBytes("GBK");String utf = new String(gbkByte, "UTF-8");System.out.print("gbk Byte");printHex(gbkByte);System.out.println("revert UTF8" + utf);System.out.println("==="); // 如果gbk變成iso-8859-1就沒問題 }public static void printHex(byte[] byteArray) {StringBuffer sb = new StringBuffer();for (byte b : byteArray) {sb.append(Integer.toHexString((b >> 4) & 0xF));sb.append(Integer.toHexString(b & 0xF));sb.append(" ");}System.out.println(sb.toString()); };public static void main(String[] args) throws Exception {String str1 = "姓名";String str2 = "用戶名";demo(str1,"UTF-8","ISO-8859-1");demo(str2,"UTF-8","ISO-8859-1");demo(str1,"UTF-8","GBK");demo(str2,"UTF-8","GBK"); }

輸出結果

原文姓名 UTF-8 Bytee5 a7 93 e5 90 8d to ISO-8859-1:?§“? ISO-8859-1 Bytee5 a7 93 e5 90 8d revert UTF-8姓名 === 原文用戶名 UTF-8 Bytee7 94 a8 e6 88 b7 e5 90 8d to ISO-8859-1:?”¨??·? ISO-8859-1 Bytee7 94 a8 e6 88 b7 e5 90 8d revert UTF-8用戶名 === 原文姓名 UTF-8 Bytee5 a7 93 e5 90 8d to GBK:濮撳悕 GBK Bytee5 a7 93 e5 90 8d revert UTF-8姓名 === 原文用戶名 UTF-8 Bytee7 94 a8 e6 88 b7 e5 90 8d to GBK:鐢ㄦ埛鍚 GBK Bytee7 94 a8 e6 88 b7 e5 90 3f revert UTF-8用戶? ===

為什么GBK會出錯

前三段都沒問題最后一段奇數個漢字的utf-8字節流轉成GBK字符串再轉回來前面一切正常最后一個字節變成了 “0x3f”即”?”

我們使用”用戶名” 三個字來分析它的UTF-8 的字節流為

[e7 94 a8] [e6 88 b7] [e5 90 8d]

我們按照三個字節一組分組他被用戶A當做一個整體交給用戶B。

用戶B由于不知道是什么字符集他當做GBK處理因為GBK是雙字節編碼如下按照兩兩一組進行分組

[e7 94] [a8 e6] [88 b7] [e5 90] [8d ]

不夠了怎么辦它把 0x8d當做一個未知字符用一個半角Ascii字符的 “” 代替變成了

[e7 94] [a8 e6] [88 b7] [e5 90] 3f

數據被破壞了。

為什么 ISO-8859-1 沒問題

因為 ISO-8859-1 是單字節編碼因此它的分組方案是

[e7] [94] [a8] [e6] [88] [b7] [e5] [90] [8d]

因此中間不做任何操作交回個用戶A的時候數據沒有變化。

關于Unicode編碼

因為UTF-16 區分大小端嚴格講unicode==UTF16BE。

public static void main(String[] args) throws Exception {String str="測試";printHex(str.getBytes("UNICODE"));printHex(str.getBytes("UTF-16LE"));printHex(str.getBytes("UTF-16BE")); }

運行結果

fe ff 6d 4b 8b d5 4b 6d d5 8b 6d 4b 8b d5

其中 “fe ff” 為大端消息頭同理小端消息頭為 “ff fe”。

小結

作為中間轉存方案ISO-8859-1 是安全的。

UTF-8 字節流用GBK字符集中轉是不安全的反過來也是同樣的道理。

byte[] utfByte = str.getBytes("UTF-8"); String gbk = new String(utfByte, "GBK"); 這是錯誤的用法雖然在ISO-8859-1時并沒報錯。首先byte[] utfByte = str.getBytes("UTF-8"); 執行完成之后utfByte 已經很明確這是utf-8格式的字節流然后gbk = new String(utfByte, "GBK") 對utf-8的字節流使用gbk解碼這是不合規矩的。就好比一個美國人說一段英語讓一個不懂英文又不會學舌的日本人聽然后傳遞消息給另一個美國人。為什么ISO-8859-1 沒問題呢因為它只認識一個一個的字節就相當于是一個錄音機。我管你說的什么鬼話連篇過去直接播放就可以了。

getBytes() 是會丟失數據的操作而且不一定會拋異常。

unicode是安全的因為他是java使用的標準類型跨平臺無差異。

總結

以上是生活随笔為你收集整理的再谈java乱码:GBK和UTF-8互转尾部乱码问题分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲视频自拍 | 五月亚洲婷婷 | 国产原创剧情av | 干爹你真棒插曲mv在线观看 | 天天干天天操天天爱 | 精品国产1区 | ts人妖另类精品视频系列 | 国产又粗又长又大视频 | 国产中文字幕在线免费观看 | 奴性白洁会所调教 | 少妇高潮一区二区三区99欧美 | 永久免费未满蜜桃 | 精品动漫一区二区三区的观看方式 | 日本成片网 | 亚洲欧美成人一区二区 | 久久精品a亚洲国产v高清不卡 | 亚洲色图首页 | 天天爽天天爽天天爽 | 久久国产美女视频 | 欧美91| 日日操日日| 中文字幕人妻一区二区三区视频 | 992tv在线影院 | 日韩高清免费av | 欧美日韩在线视频免费 | 在线国产91 | 妓院一钑片免看黄大片 | 国产不卡av在线 | 亚洲视频色图 | 少妇中文字幕 | 亚洲性生活大片 | 日产av在线播放 | 中文字幕自拍偷拍 | 欧美日韩字幕 | 亚洲第一视频 | 精品成人无码一区二区三区 | 国产精品免费一区二区三区在线观看 | 国产成人精品一区二区三区在线 | 日本wwwxxx | 国产99精品视频 | 天堂av日韩 | 亚洲天堂一区二区在线 | a√天堂网| 草久免费视频 | 狠狠干精品 | 草草视频在线 | 青娱乐在线免费观看 | 麻豆影视网站 | 人妻精品一区一区三区蜜桃91 | 少妇精品视频 | 久久无码人妻精品一区二区三区 | 婷婷激情社区 | 天堂精品久久 | 九七影院在线观看免费观看电视 | 久久91亚洲人成电影网站 | xxxⅹ少妇少妇xxxx | 91免费网站在线观看 | 午夜av福利 | 爱爱视频在线播放 | 大奶在线播放 | 欧美日韩在线观看成人 | 91免费观看视频 | 精品人妻一区二区乱码 | 欧美人妻精品一区二区 | 射综合网 | 97视频在线观看免费高清完整版在线观看 | 一级久久| 麻豆网站在线 | 精品久久久久久中文字幕 | 青青草视频在线免费观看 | 国产欧美一区二区三区在线看蜜臀 | 国产成人啪一区二区 | 国产69久久 | 日韩在线视频网 | 亚洲最大的成人网站 | 日韩毛片中文字幕 | 一区二区av | 欧美一级成人 | 人妻无码一区二区三区久久 | av色婷婷| 色黄啪啪网 | 日韩在线精品 | 九九热在线播放 | 性折磨bdsm欧美激情另类 | 国产传媒视频在线 | 国产真实乱人偷精品人妻 | 亚洲www在线 | 日韩国产欧美一区二区三区 | 久久久99国产精品免费 | 水蜜桃av在线| 在线免费av网址 | 久久久免费av | 国产午夜电影 | 91色在线视频 | 国产经典毛片 | 欧美精品黑人 | 日韩精品一区二区免费视频 | 久久久久久人妻一区二区三区 | 国产欧美熟妇另类久久久 |