看了孫鑫老師的相關(guān)講解后,總結(jié)一下。



首先看清楚幾種常用的字符集編碼(java語言是采用unicode字符集編碼來表示字符與字符串的):
ASCII(American Standard Code for Information Interchange,美國(guó)信息互換標(biāo)準(zhǔn)代碼),是基于常用的英文字符的一套電腦編碼系統(tǒng)。我們知道英文中經(jīng)常使用的字符、數(shù)字符號(hào)被計(jì)算機(jī)處理時(shí)都是以二進(jìn)制碼的形式出現(xiàn)的。這種二進(jìn)制碼的集合就是所謂的ASCII碼。每一個(gè)ASCII碼與一個(gè)8位(bit)二進(jìn)制數(shù)對(duì)應(yīng)。其最高位是0,相應(yīng)的十進(jìn)制數(shù)是0-127。如,數(shù)字“0”的編碼用十進(jìn)制數(shù)表示就是48。另有128個(gè)擴(kuò)展的ASCII碼,最高位都是1,由一些制表符和其它符號(hào)組成。ASCII是現(xiàn)今最通用的單字節(jié)編碼系統(tǒng)。
? GB2312:GB2312碼是中華人民共和國(guó)國(guó)家漢字信息交換用編碼,全稱《信息交換用漢字編碼字符集-基本集》。主要用于給每一個(gè)中文字符指定相應(yīng)的數(shù)字,也就是進(jìn)行編碼。一個(gè)中文字符用兩個(gè)字節(jié)的數(shù)字來表示,為了和ASCII碼有所區(qū)別,將中文字符每一個(gè)字節(jié)的最高位置都用1來表示。
GBK:為了對(duì)更多的字符進(jìn)行編碼,國(guó)家又發(fā)布了新的編碼系統(tǒng)GBK(GBK的K是“擴(kuò)展”的漢語拼音第一個(gè)字母)。在新的編碼系統(tǒng)里,除了完全兼容GB2312 外,還對(duì)繁體中文、一些不常用的漢字和許多符號(hào)進(jìn)行了編碼。
ISO-8859-1:是西方國(guó)家所使用的字符編碼集,是一種單字節(jié)的字符集 ,而英文實(shí)際上只用了其中數(shù)字小于128的部分。
Unicode:這是一種通用的字符集,對(duì)所有語言的文字進(jìn)行了統(tǒng)一編碼,對(duì)每一個(gè)字符都用2個(gè)字節(jié)來表示,對(duì)于英文字符采取前面加“0”字節(jié)的策略實(shí)現(xiàn)等長(zhǎng)兼容。如 “a” 的ASCII碼為0x61,UNICODE就為0x00,0x61。
UTF-8:Eight-bit UCS Transformation Format,(UCS,Universal Character Set,通用字符集,UCS 是所有其他字符集標(biāo)準(zhǔn)的一個(gè)超集)。一個(gè)7位的ASCII碼值,對(duì)應(yīng)的UTF碼是一個(gè)字節(jié)。如果字符是0x0000,或在0x0080與0x007f之間,對(duì)應(yīng)的UTF碼是兩個(gè)字節(jié),如果字符在0x0800與0xffff之間,對(duì)應(yīng)的UTF碼是三個(gè)字節(jié)。
??
這是因?yàn)镴AVA中默認(rèn)的編碼方式是UNICODE,而中國(guó)人通常使用的文件和DB都是基于GB2312或者BIG5等編碼,故會(huì)出現(xiàn)此問題。以前我也經(jīng)常為這個(gè)問題而苦惱,后來經(jīng)查了些資料,終于解決了,我知道一定有很多朋友也會(huì)碰到這個(gè)問題,所以特就總結(jié)了一下,來拿出
來讓大家一起分享了。??
1、在網(wǎng)頁中輸出中文。??
JAVA在網(wǎng)絡(luò)傳輸中使用的編碼是"ISO-8859-1",故在輸出時(shí)需要進(jìn)行轉(zhuǎn)化,如:??
String str="中文";??
str=new String(str.getBytes("GB2312"),"8859_1");??
但如果在編譯程序時(shí),使用的編碼是“GB2312”,且在中文平臺(tái)上運(yùn)行此程序,不會(huì)出現(xiàn)此
問題,一定要注意。
??
2、從參數(shù)中讀取中文??
這正好與在網(wǎng)頁中輸出相反如:??
str=new String(str.getBytes("8859_1"),"GB2312");??
3、操作DB中的中文問題??
一個(gè)較簡(jiǎn)單的方法是:在“控制面扳”中,把“區(qū)域”設(shè)置為“英語(美國(guó))”。如果還會(huì)
出現(xiàn)亂碼,還可進(jìn)行如下設(shè)置:??
取中文時(shí):str=new String(str.getBytes("GB2312"));??
向DB中輸入中文:str=new String(str.getBytes("ISO-8859-1"));??
4、在JSP中的中文解決:??
在“控制面扳”中,把“區(qū)域”設(shè)置為“英語(美國(guó))”.??
在JSP頁面中加入:??
如果還不行正常顯示,則還要進(jìn)行下面的轉(zhuǎn)換:??
如:name=new String(name.getBytes("ISO-8859-1"),"GBK");??
就不會(huì)出現(xiàn)中文問題了。
我們運(yùn)行java程序時(shí),JVM有自己所支持的編碼種類,用以下代碼可以看到:









?然后可以通過以下代碼看到我們目前JVM所使用的編碼:


具體來說什么是編碼,什么是解碼?
在InputStreamReader JDK有這樣描述:It reads bytes and decodes them into characters using a specified charset.(用指定的字符集將字節(jié)數(shù)組解碼成字符串)。
相反OutputStreamWriter 描述:Characters written to it are encoded into bytes using a specified charset.(用指定的字符集將字符串編碼成字節(jié)數(shù)組)。
理解這個(gè)以后一切好辦了啦!
我們的OS一般是GBK編碼的(凡是從磁盤上讀取文件可以看成是用OS的字符集編碼方式來對(duì)操作對(duì)象進(jìn)行解碼處理--從標(biāo)準(zhǔn)輸入設(shè)備讀取數(shù)據(jù)的時(shí)候是依賴OS的字符集)。而我們將從磁盤上文件經(jīng)過處理得到我們想要的字符串等其它對(duì)象的時(shí)候,這一過程是用JVM的默認(rèn)的字符集編碼方式來處理的!由于不同的字符集編碼方式有著不同的原理(前面所述),這樣當(dāng)編碼與解碼不一致的時(shí)候,自然而然就出現(xiàn)了可愛的亂碼。
比如如下,將我們JVM字符集改成iso-8859-1這樣在就與我們的OS不同:
當(dāng)輸入中文時(shí)自然就輸出的是亂碼了。













這時(shí)我們可以用string的一個(gè)構(gòu)造方法:
String(byt[]?bytes,?String?charsetName)?
Constructs?a?new?String?by?decoding?the?specified?array?of?bytes?using?the?specified?charset.(用指定的字符集對(duì)字節(jié)數(shù)組進(jìn)行解碼)。
其中用到了string 的getBytes方法:
getBytes(String charsetName)
Encodes this String into a sequence of bytes using the named charset, storing the result into a new byte array.(用指定的字符集進(jìn)行編碼,將結(jié)果存放到一字節(jié)數(shù)組里面)重新構(gòu)造一個(gè)string:

這樣又可以重新得到我們想要的漢字了。
我們這例子中是GBK(OS)來編碼的,然后采用iso-8859-1(JVM)來解碼得到一個(gè)新string(此string是亂碼),然后將此string用iso-8859-1重新編碼,并且用指定的GBK來解碼。得到一個(gè)新string(也就是strGBK),這個(gè)string就不再是亂碼了。
但如果我們一開始就采用GBK解碼得到的字符串,然后用ISO-8859-1編碼,能否再解碼回去得到我們的中文字符呢?顯示不可以啦,因?yàn)橛肐SO-8859-1的編碼的時(shí)候采用是一種單字節(jié)的字符集來對(duì)其編碼,這樣就丟失了一個(gè)字節(jié)(對(duì)中文來說)!所以這樣是得不到中文字符的!
2:讀取Property文件時(shí)亂碼處理
首先,我們的property文件大約如下:



??????? 亂碼其實(shí)簡(jiǎn)單,只是開始的時(shí)候沒注意罷了.我們的機(jī)器編碼應(yīng)該是GBK方式的,而在JVM程序中讀取Property文件的時(shí)候使用的是Unicode編碼方式,(我的這些處理過程也沒對(duì)編碼文件請(qǐng)求進(jìn)行過濾),所以我們可以對(duì)其進(jìn)行對(duì)應(yīng)的編碼.我是利用了JDK自帶的native2ascii.exe工具.通過--encoding 來指定其編碼方式
native2ascii -encoding GBK sourcefilename? destfilename?
這樣你在
InputStream?in?=?this.getClass().getResourceAsStream("/conf/netedu.properties");?????????? //得到class/conf包中的資源文件
語句中用到的/conf/netedu.properties文件就是destfilename?來代替就OK了
只是這樣你看到的可能是如下的一些代碼:



當(dāng)然你不可能對(duì)著一大堆的16進(jìn)制看吧,所以可以通過 -reverse 來解碼.
native2ascii -reverse? sourcefilename? destfilename?