亂碼問題經常碰到,而且每次都要花很久時間才能解決。最近想搞清楚一些實質性的東西,看了一些關于這方面的資料,在這里做個記錄
造成字符亂碼問題的原因有兩個:
1是編碼很解碼的方式不一致,
2是采用了錯誤的編碼造成數據丟失。
由于計算機的最小存儲單元是字節即8位二進制數,中文是無法在內存中直接表示的,所以從字符到字節就需要通過某個規則轉換即編碼
編碼方式有很多 我比較常用的是utf-8 GBK iso-8859-1和ASCII,這些都可以看成是字典表。
比如我用utf-8的方式去編碼字符串"你好"
String str = "你好";
byte[] utf8 = str.getBytes("utf-8");
for(byte b : utf8){
System.out.print(" "+b);
}
輸出的結果是: -28 -67 -96 -27 -91 -67
說明“你好”這個字符串被編碼成了 6個字節,utf-8是用三個字節表示一個中文字符的,這種轉換過程相當于我們查字典
如果用GBK編碼
String str = "你好";
byte[] gbk = str.getBytes("GBK");
for(byte b : gbk){
System.out.print(" "+b);
}
得到的結果是: -60 -29 -70 -61 GBK是用兩個字節表示一個中文字符的(需要注意getBytes()這個方法有兩種形式 一個是帶參數一個不帶參數,
不帶參用系統默認編碼,中文windows操作系統一般都是GBK 一種查看系統編碼的方式是用命令行chcp 936表示GBK)
到這里我們就可以解釋我們的第一個原因
比如我們用從網絡中去抓取數據的時候,對方用GBK方式進行編碼,我們拿到字節流的時候用utf-8進行解碼,
百度用的是GBK編碼
URL url = new URL("http://www.baidu.com/");
URLConnection connection = url.openConnection();
InputStream inputStream = connection.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(reader);
System.out.println("bufferedReader = " + bufferedReader.readLine());
得到的結果是:
bufferedReader = <!doctype html><html><head><meta http-equiv="Content-Type" content="text/html;charset=gb2312"><title>????????????? 。。。。
如果是GBK解碼字節流得到如下的結果
<!doctype html><html><head><meta http-equiv="Content-Type" content="text/html;charset=gb2312"><title>百度一下,你就知道 。。。。
由于編解碼方式不一致,utf8去解碼字節流的時候從“字典”中查不到相應的字符,
默認(有幾種 “?"也是我們經常見到的一種)用U+003F代替 即 “?”
這里有個問題我還沒有搞清楚,我用GBK編碼”你好“再用utf-8解碼得到的是3個”?“ 為什么是3個"?"
如果了解utf-8 GBK和iso-8859-1等這些的具體編碼方式,第二個問題就比較清楚了。
比如iso-8859-1是單字節編碼的,比起ASSCII,iso-8859-1把一個字節的最高位也納入進來表示字符,但是最多也只有256個字符,
實際上它是在ASSCII基礎之上加入了一些西歐字符,并沒有加入中文,所以iso-8859-1也不能表示中文,如果我們這么寫
String str = "你好";
byte[] bytes = str.getBytes("iso-8859-1");
System.out.println("bytes = " + new String(bytes,"utf-8")); /////輸出 ??
System.out.println("bytes = " + new String(bytes,"GBK")); /////輸出 ??
System.out.println("bytes = " + new String(bytes,"iso-8859-1")); /////輸出 ??
由于在“字典”中找不到相應的值,就用3f替代 我們用上面的方式打印 得到的都會是"??",
java用的是Unicode編碼,API中Character類下有描述:“字符信息基于 Unicode 標準,版本 4.0。。。”
更實際的Web編程中遇到的瀏覽器顯示亂碼和應用程序接收提交過去的亂碼問題以下博客中都有詳細的描述,