前幾天在使用中興的MM7接口開發一個彩信的應用,但是在測試的時候,手機收到的文本內容老是一堆亂碼,無論怎麼修改參數問題都得不到解決,因而就狠狠的琢磨和研究了下關於編碼的內容,最終成功解決了亂碼的問題。java
咱們都知道Java語言使用的是Unicode編碼。但是你們是否真的已經理解了這句話的含義? Unicode編碼和咱們經常使用的UTF-8,GBK有什麼關係呢? 那接下來就來討論下這個話題。數據庫
不知你們還有沒想過,咱們在Java代碼裏面定義一個字符串字面量的時候,該字符串在JVM中的編碼是什麼? 是的,上面也說了Java語言用的是Unicode編碼,因此這樣定義的字符串字面量天然就是Unicode編碼表示的。 然而除了這種程序內部的數據外,咱們常常還會從外部獲取各類各樣的數據讓程序處理,例如經過IO從硬盤上讀取文件,經過JDBC查詢數據庫等,而這些數據的編碼格式是多種多樣的,例若有的多是UTF-8,有的多是GBK等,那麼這樣的一些數據在JVM中又是以什麼編碼表示的呢?數組
上面提到了幾個問題,如今返回去簡單的說說編碼,固然這裏只是粗略的說起,畢竟網上這方面的內容不少。ide
咱們首先要弄清楚兩個概念,「字符集編碼」和「編碼格式」。所謂「字符集編碼」就是由某個組織制定的一張「字符與編號的映射關係表」,例如: 10001 == 「我」, 10002 = 「們」。 咱們所謂的Unicode字符集就是這樣的一張關係表。測試
而UTF-8是一種實現了Unicode字符集中部分字符編碼的「編碼格式」,它存在目的是爲了保存或者傳輸數據用的。那麼既然在字符集中已經有了映射關係了,爲何還要再來編碼。緣由好幾個,例如考慮文件大小的問題,使用效率的問題,和其餘字符集區分的問題等。編碼
那麼UTF-8編碼又是對Unicode字符集中的哪部分編碼呢? 就是「字符編號」,例如上面的10001,10002. 而對於UTF-8的編碼規則能夠網上查閱.操作系統
那如今咱們就應該清楚了,在JVM中表示字符串「咱們」使用的編碼爲「1000110002」這樣的格式,也就是使用的是Unicode的編號。那當咱們經過IO將一個以UTF-8編碼的文本文件讀入內存的時候,極可能咱們會使用到這樣的代碼:code
new InputStreamReader(new FileInputStream(file),"UTF-8")對象
這裏指定的「UTF-8」就是文件的編碼格式,它的目的是告訴負責解碼的對象要按照「UTF-8」的編碼格式來解碼成JVM使用的Unicode編碼。那若是咱們這裏指定爲「GBK」的話,咱們所獲得的可就是一堆亂碼啦。接口
若是String content = (文件內容) 。 那麼這個content在這個時候已是Unicode編碼了。不知道如今爲止是否應該明白了些什麼。
若是你看到這樣的代碼:
String msg = "我是一個字符串" ;
String res = new String(msg.getBytes("utf-8"),"GBK") ;
那這裏的res打印出來也就是一堆亂碼了。這裏的操做過程實際上是:
1,將Unicode編碼的msg按照UTF-8的編碼格式進行編碼,從而獲得UTF-8編碼的字節數組。
2,將字節數組按照GBK的編碼格式來解碼成Unicode編碼的字符
3,惋惜UTF-8和GBK不兼容,他們使用了不一樣的編碼集,因此亂碼出來啦
在進行http請求的時候,咱們須要告訴對方咱們發送的數據的編碼格式是什麼,若是對方按照咱們的告知的編碼格式來解碼,而咱們卻把錯誤的編碼格式告訴了對方,那麼接下來的事情就是對方收到了一堆的亂碼。
還有就是咱們在進行這樣的操做的時候:"我是一個字符串".getBytes(); 可要當心了,這個時候獲得的字節數組但是你操做系統默認的編碼格式(固然咱們還能夠在啓動的時候指定咱們默認的編碼格式)。
下面再追加點編碼解碼的例子,供你們理會:
//定義一個Unicode字符類型的字符串 String msg = "我是一個字符串哦,仍是Unicode編碼的。體發財" ; System.out.println("原有字符串:"+msg); System.out.println("============="); //將Unicode編碼按照GBK編碼格式進行編碼 byte[] gbkbyts = msg.getBytes("GBK"); /* * 原本是GBK編碼的字節,咱們使用UTF-8來解碼.固然此時必然會是亂碼。 * * 注意:若是在第一次解碼的時候使用這種錯誤的解碼方式, * 那麼後面將沒法再恢復,下面的例子能夠看到。 * */ String utf8Str = new String(gbkbyts,"UTF-8") ; System.out.println("UTF-8解碼後的字符串:"+utf8Str); /* * 接下來咱們把該字符串按照UTF-8的編碼格式再編碼回去. * 但這個時候gbkbyts和utf8Byts已經徹底不一樣了。 * */ byte[] utf8Byts = utf8Str.getBytes("UTF-8") ; /* * 接着咱們再來按照GBK的編碼格式來解碼. * 獲得的天然是亂碼。 * */ String utf2GbkStr = new String(utf8Byts,"GBK") ; System.out.println("GBK解碼UTF-8編碼後的字符串:"+utf2GbkStr); System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); /* * 可是,若是咱們第一次解碼的時候使用的是單字節的編碼格式來解碼,那後面是能夠再恢復的。 * 但是還有一個要求,就是要保證該單字節的編碼會利用上全部的8位, * 也就是說能夠表示256個字符的才行。 * * *單字節的編碼格式有兩種, ASCII和ISO-8859-? *ASCII使用了7位來表示字符,最高位永遠爲0,其能夠表示的範圍只有128個字符。 *ISO-8859-?(問號表示1,2,3…11,13…16,沒有12,表示15個字符集) *使用8位來表示字符,總共能夠表示256個字符。 * *這兩種單字節編碼,咱們最經常使用的也就是ISO-8859-1 * */ //轉換爲ASCII碼的字符串 String ascStr = new String(gbkbyts,"ASCII") ; System.out.println("ASCII解碼後的字符串:"+ascStr); //再將ASCII轉換爲GBK String gbkStr = new String(ascStr.getBytes("ASCII"),"GBK") ; System.out.println("將ASCII編碼按照GBK編碼格式解碼:"+gbkStr); System.out.println("==============================="); String isoStr = new String(gbkbyts,"ISO-8859-1") ; System.out.println("ISO-8859-1解碼後的字符串:"+ascStr); //再將ASCII轉換爲GBK String gbkStr1 = new String(isoStr.getBytes("ISO-8859-1"),"GBK") ; System.out.println("將ISO-8859-1編碼按照GBK編碼格式解碼:"+gbkStr1);
其運行結果以下:
原有字符串:我是一個字符串哦,仍是Unicode編碼的。體發財 ============= UTF-8解碼後的字符串:???????????????????Unicode???????w?l? GBK解碼UTF-8編碼後的字符串:錕斤拷錕斤拷一錕斤拷錕街鳳拷錕斤拷哦錕斤拷錕斤拷錕斤拷Unicode錕斤拷錕斤拷摹錕斤拷w錕絣財 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ASCII解碼後的字符串:??????????????????????Unicode?????????w?l?? 將ASCII編碼按照GBK編碼格式解碼:??????????????????????Unicode?????????w?l?? =============================== ISO-8859-1解碼後的字符串:??????????????????????Unicode?????????w?l?? 將ISO-8859-1編碼按照GBK編碼格式解碼:我是一個字符串哦,仍是Unicode編碼的。體發財
以上的內容大概的講了下關於java中編碼的問題,也算是一個拋磚引玉的過程,歡迎指正。