亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java字符編碼簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

 更新時(shí)間:2017年08月14日 10:31:22   投稿:mrr  
這篇文章主要介紹了Java字符編碼簡(jiǎn)介,本文主要包括以下幾個(gè)方面:編碼基本知識(shí),Java,系統(tǒng)軟件,url,工具軟件等,感興趣的朋友一起看看吧

1. 概述

本文主要包括以下幾個(gè)方面:編碼基本知識(shí),Java,系統(tǒng)軟件,url,工具軟件等。

在下面的描述中,將以"中文"兩個(gè)字為例,經(jīng)查表可以知道其GB2312編碼是"d6d0 cec4",Unicode編碼為"4e2d 6587",UTF編碼就是"e4b8ad e69687"。注意,這兩個(gè)字沒(méi)有iso8859-1編碼,但可以用iso8859-1編碼來(lái)"表示"。

2. 編碼基本知識(shí)

最早的編碼是iso8859-1,和ascii編碼相似。但為了方便表示各種各樣的語(yǔ)言,逐漸出現(xiàn)了很多標(biāo)準(zhǔn)編碼,重要的有如下幾個(gè)。

2.1. iso8859-1

屬于單字節(jié)編碼,最多能表示的字符范圍是0-255,應(yīng)用于英文系列。比如,字母'a'的編碼為0x61=97。很明顯,iso8859-1編碼表示的字符范圍很窄,無(wú)法表示中文字符。但是,由于是單字節(jié)編碼,和計(jì)算機(jī)最基礎(chǔ)的表示單位一致,所以很多時(shí)候,仍舊使用iso8859-1編碼來(lái)表示。而且在很多協(xié)議上,默認(rèn)使用該編碼。比如,雖然"中文"兩個(gè)字不存在iso8859-1編碼,以gb2312編碼為例,應(yīng)該是"d6d0 cec4"兩個(gè)字符,使用iso8859-1編碼的時(shí)候則將它拆開(kāi)為4個(gè)字節(jié)來(lái)表示:"d6 d0 ce c4"(事實(shí)上,在進(jìn)行存儲(chǔ)的時(shí)候,也是以字節(jié)為單位處理的)。而如果是UTF編碼,則是6個(gè)字節(jié)"e4 b8 ad e6 96 87"。很明顯,這種表示方法還需要以另一種編碼為基礎(chǔ)。

2.2. GB2312/GBK

這就是漢子的國(guó)標(biāo)碼,專門用來(lái)表示漢字,是雙字節(jié)編碼,而英文字母和iso8859-1一致(兼容iso8859-1編碼)。其中g(shù)bk編碼能夠用來(lái)同時(shí)表示繁體字和簡(jiǎn)體字,而gb2312只能表示簡(jiǎn)體字,gbk是兼容gb2312編碼的。

2.3. unicode

這是最統(tǒng)一的編碼,可以用來(lái)表示所有語(yǔ)言的字符,而且是定長(zhǎng)雙字節(jié)(也有四字節(jié)的)編碼,包括英文字母在內(nèi)。所以可以說(shuō)它是不兼容iso8859-1編碼的,也不兼容任何編碼。不過(guò),相對(duì)于iso8859-1編碼來(lái)說(shuō),uniocode編碼只是在前面增加了一個(gè)0字節(jié),比如字母'a'為"00 61"。

需要說(shuō)明的是,定長(zhǎng)編碼便于計(jì)算機(jī)處理(注意GB2312/GBK不是定長(zhǎng)編碼),而unicode又可以用來(lái)表示所有字符,所以在很多軟件內(nèi)部是使用unicode編碼來(lái)處理的,比如java。

2.4. UTF

考慮到unicode編碼不兼容iso8859-1編碼,而且容易占用更多的空間:因?yàn)閷?duì)于英文字母,unicode也需要兩個(gè)字節(jié)來(lái)表示。所以u(píng)nicode不便于傳輸和存儲(chǔ)。因此而產(chǎn)生了utf編碼,utf編碼兼容iso8859-1編碼,同時(shí)也可以用來(lái)表示所有語(yǔ)言的字符,不過(guò),utf編碼是不定長(zhǎng)編碼,每一個(gè)字符的長(zhǎng)度從1-6個(gè)字節(jié)不等。另外,utf編碼自帶簡(jiǎn)單的校驗(yàn)功能。一般來(lái)講,英文字母都是用一個(gè)字節(jié)表示,而漢字使用三個(gè)字節(jié)。

注意,雖然說(shuō)utf是為了使用更少的空間而使用的,但那只是相對(duì)于unicode編碼來(lái)說(shuō),如果已經(jīng)知道是漢字,則使用GB2312/GBK無(wú)疑是最節(jié)省的。不過(guò)另一方面,值得說(shuō)明的是,雖然utf編碼對(duì)漢字使用3個(gè)字節(jié),但即使對(duì)于漢字網(wǎng)頁(yè),utf編碼也會(huì)比unicode編碼節(jié)省,因?yàn)榫W(wǎng)頁(yè)中包含了很多的英文字符。

3. java對(duì)字符的處理

在java應(yīng)用軟件中,會(huì)有多處涉及到字符集編碼,有些地方需要進(jìn)行正確的設(shè)置,有些地方需要進(jìn)行一定程度的處理。

3.1. getBytes(charset)

這是java字符串處理的一個(gè)標(biāo)準(zhǔn)函數(shù),其作用是將字符串所表示的字符按照charset編碼,并以字節(jié)方式表示。注意字符串在java內(nèi)存中總是按unicode編碼存儲(chǔ)的。比如"中文",正常情況下(即沒(méi)有錯(cuò)誤的時(shí)候)存儲(chǔ)為"4e2d 6587",如果charset為"gbk",則被編碼為"d6d0 cec4",
然后返回字節(jié)"d6 d0 ce c4"。如果charset為"utf8"則最后是"e4 b8 ad e6 96 87"。如果是"iso8859-1",則由于無(wú)法編碼,最后返回 "3f 3f"(兩個(gè)問(wèn)號(hào))。

3.2. new String(charset)

這是java字符串處理的另一個(gè)標(biāo)準(zhǔn)函數(shù),和上一個(gè)函數(shù)的作用相反,將字節(jié)數(shù)組按照charset編碼進(jìn)行組合識(shí)別,最后轉(zhuǎn)換為unicode存儲(chǔ)。參考上述getBytes的例子,"gbk" 和"utf8"都可以得出正確的結(jié)果"4e2d 6587",但iso8859-1最后變成了"003f 003f"(兩個(gè)問(wèn)號(hào))。

因?yàn)閡tf8可以用來(lái)表示/編碼所有字符,所以new String( str.getBytes("utf8" ), "utf8" ) === str,即完全可逆。

3.3.setCharacterEncoding()

該函數(shù)用來(lái)設(shè)置http請(qǐng)求或者相應(yīng)的編碼。

對(duì)于request,是指提交內(nèi)容的編碼,指定后可以通過(guò)getParameter()則直接獲得正確的字符串,如果不指定,則默認(rèn)使用iso8859-1編碼,需要進(jìn)一步處理。參見(jiàn)下述"表單輸入"。值得注意的是在執(zhí)行setCharacterEncoding()之前,不能執(zhí)行任何getParameter()。java doc上說(shuō)明:This method must be called prior toreading request parameters or reading input using getReader()。而且,該指定只對(duì)POST方法有效,對(duì)GET方法無(wú)效。分析原因,應(yīng)該是在執(zhí)行第一個(gè)getParameter()的時(shí)候,java將會(huì)按照編碼分析所有的提交內(nèi)容,而后續(xù)的getParameter()不再進(jìn)行分析,所以setCharacterEncoding()無(wú)效。而對(duì)于GET方法提交表單是,提交的內(nèi)容在URL中,一開(kāi)始就已經(jīng)按照編碼分析所有的提交內(nèi)容,setCharacterEncoding()自然就無(wú)效。
對(duì)于response,則是指定輸出內(nèi)容的編碼,同時(shí),該設(shè)置會(huì)傳遞給瀏覽器,告訴瀏覽器輸出內(nèi)容所采用的編碼。

3.4. 處理過(guò)程

下面分析兩個(gè)有代表性的例子,說(shuō)明java對(duì)編碼有關(guān)問(wèn)題的處理方法。

3.4.1. 表單輸入

User input  *(gbk:d6d0cec4)  browser  *(gbk:d6d0 cec4)  web server iso8859-1(00d6 00d 000ce 00c4)  class,需要在class中進(jìn)行處理:getbytes("iso8859-1")為d6 d0 ce c4,new String("gbk")為d6d0 cec4,內(nèi)存中以u(píng)nicode編碼則為4e2d 6587。

l 用戶輸入的編碼方式和頁(yè)面指定的編碼有關(guān),也和用戶的操作系統(tǒng)有關(guān),所以是不確定的,上例以gbk為例。

l 從browser到web server,可以在表單中指定提交內(nèi)容時(shí)使用的字符集,否則會(huì)使用頁(yè)面指定的編碼。而如果在url中直接用?的方式輸入?yún)?shù),則其編碼往往是操作系統(tǒng)本身的編碼,因?yàn)檫@時(shí)和頁(yè)面無(wú)關(guān)。上述仍舊以gbk編碼為例。

l Webserver接收到的是字節(jié)流,默認(rèn)時(shí)(getParameter)會(huì)以iso8859-1編碼處理之,結(jié)果是不正確的,所以需要進(jìn)行處理。但如果預(yù)先設(shè)置了編碼(通過(guò)request. setCharacterEncoding ()),則能夠直接獲取到正確的結(jié)果。

l 在頁(yè)面中指定編碼是個(gè)好習(xí)慣,否則可能失去控制,無(wú)法指定正確的編碼。

3.4.2. 文件編譯

假設(shè)文件是gbk編碼保存的,而編譯有兩種編碼選擇:gbk或者iso8859-1,前者是中文windows的默認(rèn)編碼,后者是linux的默認(rèn)編碼,當(dāng)然也可以在編譯時(shí)指定編碼。

Jsp  *(gbk:d6d0 cec4)  javafile  *(gbk:d6d0 cec4)  compiler read  uincode(gbk: 4e2d6587; iso8859-1: 00d6 00d 000ce 00c4)  compiler write  utf(gbk:e4b8ad e69687; iso8859-1: *)  compiled file  unicode(gbk: 4e2d6587; iso8859-1: 00d6 00d 000ce 00c4)  class。所以用gbk編碼保存,而用iso8859-1編譯的結(jié)果是不正確的。

class  unicode(4e2d 6587)  system.out/ jsp.out  gbk(d6d0 cec4)  os console / browser。

l 文件可以以多種編碼方式保存,中文windows下,默認(rèn)為ansi/gbk。

l 編譯器讀取文件時(shí),需要得到文件的編碼,如果未指定,則使用系統(tǒng)默認(rèn)編碼。一般class文件,是以系統(tǒng)默認(rèn)編碼保存的,所以編譯不會(huì)出問(wèn)題,但對(duì)于jsp文件,如果在中文windows下編輯保存,而部署在英文linux下運(yùn)行/編譯,則會(huì)出現(xiàn)問(wèn)題。所以需要在jsp文件中用pageEncoding指定編碼。

l Java編譯的時(shí)候會(huì)轉(zhuǎn)換成統(tǒng)一的unicode編碼處理,最后保存的時(shí)候再轉(zhuǎn)換為utf編碼。

l 當(dāng)系統(tǒng)輸出字符的時(shí)候,會(huì)按指定編碼輸出,對(duì)于中文windows下,System.out將使用gbk編碼,而對(duì)于response(瀏覽器),則使用jsp文件頭指定的contentType,或者可以直接為response指定編碼。同時(shí),會(huì)告訴browser網(wǎng)頁(yè)的編碼。如果未指定,則會(huì)使用iso8859-1編碼。對(duì)于中文,應(yīng)該為browser指定輸出字符串的編碼。

l browser顯示網(wǎng)頁(yè)的時(shí)候,首先使用response中指定的編碼(jsp文件頭指定的contentType最終也反映在response上),如果未指定,則會(huì)使用網(wǎng)頁(yè)中meta項(xiàng)指定中的contentType。

3.5. 幾處設(shè)置

對(duì)于web應(yīng)用程序,和編碼有關(guān)的設(shè)置或者函數(shù)如下。

3.5.1. jsp編譯

指定文件的存儲(chǔ)編碼,很明顯,該設(shè)置應(yīng)該置于文件的開(kāi)頭。例如:<%@pagepageEncoding="GBK"%>。另外,對(duì)于一般class文件,可以在編譯的時(shí)候指定編碼。

3.5.2. jsp輸出

指定文件輸出到browser是使用的編碼,該設(shè)置也應(yīng)該置于文件的開(kāi)頭。例如:<%@ pagecontentType="text/html; charset= GBK" %>。該設(shè)置和response.setCharacterEncoding("GBK")等效。

3.5.3. meta設(shè)置

指定網(wǎng)頁(yè)使用的編碼,該設(shè)置對(duì)靜態(tài)網(wǎng)頁(yè)尤其有作用。因?yàn)殪o態(tài)網(wǎng)頁(yè)無(wú)法采用jsp的設(shè)置,而且也無(wú)法執(zhí)行response.setCharacterEncoding()。例如:<META http-equiv="Content-Type"content="text/html; charset=GBK" />
如果同時(shí)采用了jsp輸出和meta設(shè)置兩種編碼指定方式,則jsp指定的優(yōu)先。因?yàn)閖sp指定的直接體現(xiàn)在response中。

需要注意的是,apache有一個(gè)設(shè)置可以給無(wú)編碼指定的網(wǎng)頁(yè)指定編碼,該指定等同于jsp的編碼指定方式,所以會(huì)覆蓋靜態(tài)網(wǎng)頁(yè)中的meta指定。所以有人建議關(guān)閉該設(shè)置。

3.5.4. form設(shè)置

當(dāng)瀏覽器提交表單的時(shí)候,可以指定相應(yīng)的編碼。例如:<form accept-charset= "gb2312">。一般不必不使用該設(shè)置,瀏覽器會(huì)直接使用網(wǎng)頁(yè)的編碼。

4. 系統(tǒng)軟件

下面討論幾個(gè)相關(guān)的系統(tǒng)軟件。

4.1. MySQL數(shù)據(jù)庫(kù)

很明顯,要支持多語(yǔ)言,應(yīng)該將數(shù)據(jù)庫(kù)的編碼設(shè)置成utf或者unicode,而utf更適合與存儲(chǔ)。但是,如果中文數(shù)據(jù)中包含的英文字母很少,其實(shí)unicode更為適合。
數(shù)據(jù)庫(kù)的編碼可以通過(guò)mysql的配置文件設(shè)置,例如default-character-set=utf8。還可以在數(shù)據(jù)庫(kù)鏈接URL中設(shè)置,例如:useUnicode=true&characterEncoding=UTF-8。注意這兩者應(yīng)該保持一致,在新的sql版本里,在數(shù)據(jù)庫(kù)鏈接URL里可以不進(jìn)行設(shè)置,但也不能是錯(cuò)誤的設(shè)置。

4.2. apache

appache和編碼有關(guān)的配置在httpd.conf中,例如AddDefaultCharset UTF-8。如前所述,該功能會(huì)將所有靜態(tài)頁(yè)面的編碼設(shè)置為UTF-8,最好關(guān)閉該功能。

另外,apache還有單獨(dú)的模塊來(lái)處理網(wǎng)頁(yè)響應(yīng)頭,其中也可能對(duì)編碼進(jìn)行設(shè)置。

4.3. linux默認(rèn)編碼

這里所說(shuō)的linux默認(rèn)編碼,是指運(yùn)行時(shí)的環(huán)境變量。兩個(gè)重要的環(huán)境變量是LC_ALL和LANG,默認(rèn)編碼會(huì)影響到j(luò)ava URLEncode的行為,下面有描述。

建議都設(shè)置為"zh_CN.UTF-8"。

4.4. 其它

為了支持中文文件名,linux在加載磁盤時(shí)應(yīng)該指定字符集,例如:mount /dev/hda5 /mnt/hda5/ -t ntfs -oiocharset=gb2312。

另外,如前所述,使用GET方法提交的信息不支持request.setCharacterEncoding(),但可以通過(guò)tomcat的配置文件指定字符集,在tomcat的server.xml文件中,形如:<Connector ...URIEncoding="GBK"/>。這種方法將統(tǒng)一設(shè)置所有請(qǐng)求,而不能針對(duì)具體頁(yè)面進(jìn)行設(shè)置,也不一定和browser使用的編碼相同,所以有時(shí)候并不是所期望的。

5. URL地址

URL地址中含有中文字符是很麻煩的,前面描述過(guò)使用GET方法提交表單的情況,使用GET方法時(shí),參數(shù)就是包含在URL中。

5.1. URL編碼

對(duì)于URL中的一些特殊字符,瀏覽器會(huì)自動(dòng)進(jìn)行編碼。這些字符除了"/?&"等外,還包括unicode字符,比如漢子。這時(shí)的編碼比較特殊。

IE有一個(gè)選項(xiàng)"總是使用UTF-8發(fā)送URL",當(dāng)該選項(xiàng)有效時(shí),IE將會(huì)對(duì)特殊字符進(jìn)行UTF-8編碼,同時(shí)進(jìn)行URL編碼。如果改選項(xiàng)無(wú)效,則使用默認(rèn)編碼"GBK",并且不進(jìn)行URL編碼。但是,對(duì)于URL后面的參數(shù),則總是不進(jìn)行編碼,相當(dāng)于UTF-8選項(xiàng)無(wú)效。比如"中文.html?a=中文",當(dāng)UTF-8選項(xiàng)有效時(shí),將發(fā)送鏈接"%e4%b8%ad%e6%96%87.html?a=\x4e\x2d\x65\x87";而UTF-8選項(xiàng)無(wú)效時(shí),將發(fā)送鏈接"\x4e\x2d\x65\x87.html?a=\x4e\x2d\x65\x87"。注意后者前面的"中文"兩個(gè)字只有4個(gè)字節(jié),而前者卻有18個(gè)字節(jié),這主要時(shí)URL編碼的原因。

當(dāng)web server(tomcat)接收到該鏈接時(shí),將會(huì)進(jìn)行URL解碼,即去掉"%",同時(shí)按照ISO8859-1編碼(上面已經(jīng)描述,可以使用URLEncoding來(lái)設(shè)置成其它編碼)識(shí)別。上述例子的結(jié)果分別
是"\ue4\ub8\uad\ue6\u96\u87.html?a=\u4e\u2d\u65\u87"和"\u4e\u2d\u65\u87.html?a=\u4e\u2d\u65\u87",注意前者前面的"中文"兩個(gè)字恢復(fù)成了6個(gè)字符。這里用"\u",表示是unicode。

所以,由于客戶端設(shè)置的不同,相同的鏈接,在服務(wù)器上得到了不同結(jié)果。這個(gè)問(wèn)題不少人都遇到,卻沒(méi)有很好的解決辦法。所以有的網(wǎng)站會(huì)建議用戶嘗試關(guān)閉UTF-8選項(xiàng)。不過(guò),下面會(huì)描述一個(gè)更好的處理辦法。

5.2. rewrite

熟悉的人都知道,apache有一個(gè)功能強(qiáng)大的rewrite模塊,這里不描述其功能。需要說(shuō)明的是該模塊會(huì)自動(dòng)將URL解碼(去除%),即完成上述web server(tomcat)的部分功能。有相關(guān)文檔介紹說(shuō)可以使用[NE]參數(shù)來(lái)關(guān)閉該功能,但我試驗(yàn)并未成功,可能是因?yàn)榘姹荆ㄎ沂褂玫氖?br /> apache 2.0.54)問(wèn)題。另外,當(dāng)參數(shù)中含有"?& "等符號(hào)的時(shí)候,該功能將導(dǎo)致系統(tǒng)得不到正常結(jié)果。

rewrite本身似乎完全是采用字節(jié)處理的方式,而不考慮字符串的編碼,所以不會(huì)帶來(lái)編碼問(wèn)題。

5.3. URLEncode.encode()

這是Java本身提供對(duì)的URL編碼函數(shù),完成的工作和上述UTF-8選項(xiàng)有效時(shí)瀏覽器所做的工作相似。值得說(shuō)明的是,java已經(jīng)不贊成不指定編碼來(lái)使用該方法(deprecated)。應(yīng)該在使用的時(shí)候增加編碼指定。

當(dāng)不指定編碼的時(shí)候,該方法使用系統(tǒng)默認(rèn)編碼,這會(huì)導(dǎo)致軟件運(yùn)行結(jié)果得不確定。比如對(duì)于"中文",當(dāng)系統(tǒng)默認(rèn)編碼為"gb2312"時(shí),結(jié)果是"%4e%2d%65%87",而默認(rèn)編碼為"UTF-8",結(jié)果卻是"%e4%b8%ad%e6%96%87",后續(xù)程序?qū)㈦y以處理。另外,這兒說(shuō)的系統(tǒng)默認(rèn)編碼是由運(yùn)行
tomcat時(shí)的環(huán)境變量LC_ALL和LANG等決定的,曾經(jīng)出現(xiàn)過(guò)tomcat重啟后就出現(xiàn)亂碼的問(wèn)題,最后才郁悶的發(fā)現(xiàn)是因?yàn)樾薷男薷牧诉@兩個(gè)環(huán)境變量。

建議統(tǒng)一指定為"UTF-8"編碼,可能需要修改相應(yīng)的程序。

5.4. 一個(gè)解決方案

上面說(shuō)起過(guò),因?yàn)闉g覽器設(shè)置的不同,對(duì)于同一個(gè)鏈接,web server收到的是不同內(nèi)容,而軟件系統(tǒng)有無(wú)法知道這中間的區(qū)別,所以這一協(xié)議目前還存在缺陷。
針對(duì)具體問(wèn)題,不應(yīng)該僥幸認(rèn)為所有客戶的IE設(shè)置都是UTF-8有效的,也不應(yīng)該粗暴的建議用戶修改IE設(shè)置,要知道,用戶不可能去記住每一個(gè)web server的設(shè)置。所以,接下來(lái)的解決辦法就只能是讓自己的程序多一點(diǎn)智能:根據(jù)內(nèi)容來(lái)分析編碼是否UTF-8。

比較幸運(yùn)的是UTF-8編碼相當(dāng)有規(guī)律,所以可以通過(guò)分析傳輸過(guò)來(lái)的鏈接內(nèi)容,來(lái)判斷是否是正確的UTF-8字符,如果是,則以UTF-8處理之,如果不是,則使用客戶默認(rèn)編碼(比如"GBK"),下面是一個(gè)判斷是否UTF-8的例子,如果你了解相應(yīng)規(guī)律,就容易理解。

publicstatic boolean isValidUtf8(byte[] b,int aMaxCount){ 
   int lLen=b.length,lCharCount=0; 
   for(int i=0;i<lLen && lCharCount<aMaxCount;++lCharCount){ 
       byte lByte=b[i++];//to fast operation, ++ now, ready for the following for(;;) 
       if(lByte>=0) continue;//>=0 is normal ascii 
       if(lByte<(byte)0xc0 || lByte>(byte)0xfd) return false; 
       int lCount=lByte>(byte)0xfc?5:lByte>(byte)0xf8?4 
          :lByte>(byte)0xf0?3:lByte>(byte)0xe0?2:1; 
       if(i+lCount>lLen) return false; 
       for(int j=0;j<lCount;++j,++i) if(b[i]>=(byte)0xc0) return false; 
   } 
   return true; 
} 
相應(yīng)地,一個(gè)使用上述方法的例子如下:
publicstatic String getUrlParam(String aStr,String aDefaultCharset) 
throwsUnsupportedEncodingException{ 
   if(aStr==null) return null; 
   byte[] lBytes=aStr.getBytes("ISO-8859-1"); 
   return newString(lBytes,StringUtil.isValidUtf8(lBytes)?"utf8":aDefaultCharset); 
} 

不過(guò),該方法也存在缺陷,如下兩方面:

l 沒(méi)有包括對(duì)用戶默認(rèn)編碼的識(shí)別,這可以根據(jù)請(qǐng)求信息的語(yǔ)言來(lái)判斷,但不一定正確,因?yàn)槲覀冇袝r(shí)候也會(huì)輸入一些韓文,或者其他文字。

l 可能會(huì)錯(cuò)誤判斷UTF-8字符,一個(gè)例子是"學(xué)習(xí)"兩個(gè)字,其GBK編碼是" \xd1\xa7\xcf\xb0",如果使用上述isValidUtf8方法判斷,將返回true??梢钥紤]使用更嚴(yán)格的判斷方法,不過(guò)估計(jì)效果不大。
有一個(gè)例子可以證明google也遇到了上述問(wèn)題,而且也采用了和上述相似的處理方法,比如,如果在地址欄中輸入"

最后,應(yīng)該補(bǔ)充說(shuō)明一下,如果不使用rewrite規(guī)則,或者通過(guò)表單提交數(shù)據(jù),其實(shí)并不一定會(huì)遇到上述問(wèn)題,因?yàn)檫@時(shí)可以在提交數(shù)據(jù)時(shí)指定希望的編碼。另外,中文文件名確實(shí)會(huì)帶來(lái)問(wèn)題,應(yīng)該謹(jǐn)慎使用。

6. 其它

下面描述一些和編碼有關(guān)的其他問(wèn)題。

6.1. SecureCRT

除了瀏覽器和控制臺(tái)與編碼有關(guān)外,一些客戶端也很有關(guān)系。比如在使用SecureCRT連接linux時(shí),應(yīng)該讓SecureCRT的顯示編碼(不同的session,可以有不同的編碼設(shè)置)和linux的編碼環(huán)境變量保持一致。否則看到的一些幫助信息,就可能是亂碼。

另外,mysql有自己的編碼設(shè)置,也應(yīng)該保持和SecureCRT的顯示編碼一致。否則通過(guò)SecureCRT執(zhí)行sql語(yǔ)句的時(shí)候,可能無(wú)法處理中文字符,查詢結(jié)果也會(huì)出現(xiàn)亂碼。

對(duì)于Utf-8文件,很多編輯器(比如記事本)會(huì)在文件開(kāi)頭增加三個(gè)不可見(jiàn)的標(biāo)志字節(jié),如果作為mysql的輸入文件,則必須要去掉這三個(gè)字符。(用linux的vi保存可以去掉這三個(gè)字符)。一個(gè)有趣的現(xiàn)象是,在中文windows下,創(chuàng)建一個(gè)新txt文件,用記事本打開(kāi),輸入"連通"兩個(gè)
字,保存,再打開(kāi),你會(huì)發(fā)現(xiàn)兩個(gè)字沒(méi)了,只留下一個(gè)小黑點(diǎn)。

6.2. 過(guò)濾器

如果需要統(tǒng)一設(shè)置編碼,則通過(guò)filter進(jìn)行設(shè)置是個(gè)不錯(cuò)的選擇。在filter class中,可以統(tǒng)一為需要的請(qǐng)求或者回應(yīng)設(shè)置編碼。參加上述setCharacterEncoding()。這個(gè)類apache已經(jīng)給出了可以直接使用的例子SetCharacterEncodingFilter。

6.3. POST和GET

很明顯,以POST提交信息時(shí),URL有更好的可讀性,而且可以方便的使用setCharacterEncoding()來(lái)處理字符集問(wèn)題。但GET方法形成的URL能夠更容易表達(dá)網(wǎng)頁(yè)的實(shí)際內(nèi)容,也能夠用于收藏。
從統(tǒng)一的角度考慮問(wèn)題,建議采用GET方法,這要求在程序中獲得參數(shù)是進(jìn)行特殊處理,而無(wú)法使用setCharacterEncoding()的便利,如果不考慮rewrite,就不存在IE的UTF-8問(wèn)題,可以考慮通過(guò)設(shè)置URIEncoding來(lái)方便獲取URL中的參數(shù)。

6.4. 簡(jiǎn)繁體編碼轉(zhuǎn)換

GBK同時(shí)包含簡(jiǎn)體和繁體編碼,也就是說(shuō)同一個(gè)字,由于編碼不同,在GBK編碼下屬于兩個(gè)字。有時(shí)候,為了正確取得完整的結(jié)果,應(yīng)該將繁體和簡(jiǎn)體進(jìn)行統(tǒng)一。可以考慮將UTF、GBK中的所有繁體字,轉(zhuǎn)換為相應(yīng)的簡(jiǎn)體字,BIG5編碼的數(shù)據(jù),也應(yīng)該轉(zhuǎn)化成相應(yīng)的簡(jiǎn)體字。當(dāng)然,仍舊以
UTF編碼存儲(chǔ)。

例如,對(duì)于"語(yǔ)言 語(yǔ)言",用UTF表示為"\xE8\xAF\xAD\xE8\xA8\x80 \xE8\xAA\x9E\xE8\xA8\x80",進(jìn)行簡(jiǎn)繁體編碼轉(zhuǎn)換后應(yīng)該是兩個(gè)相同的 "\xE8\xAF\xAD\xE8\xA8\x80>"。

Java與Unicode

Java與Unicode: 

Java的class文件采用utf8的編碼方式,JVM運(yùn)行時(shí)采用utf16。Java的字符串是unicode編碼的。總之,Java采用了unicode字符集,使之易于國(guó)際化。

Java支持哪些字符集: 

即Java能識(shí)別哪些字符集并對(duì)它進(jìn)行正確地處理?查看Charset 類,最新的JDK支持160種字符集??梢酝ㄟ^(guò)static方法availableCharsets拿到所有Java支持的字符集。

1.assertEquals(160, Charset.availableCharsets().size());      

2.Set<String> charsetNames = Charset.availableCharsets().keySet();       

3.assertTrue(charsetNames.contains("utf-8"));       

4.assertTrue(charsetNames.contains("utf-16"));       

5.assertTrue(charsetNames.contains("gb2312"));       

6.assertTrue(Charset.isSupported("utf-8"));    

需要在哪些時(shí)候注意編碼問(wèn)題?

1.從外部資源讀取數(shù)據(jù):

這跟外部資源采取的編碼方式有關(guān),我們需要使用外部資源采用的字符集來(lái)讀取外部數(shù)據(jù):

1.InputStream is = new FileInputStream("res/input2.data");       

2.InputStreamReader streamReader = new InputStreamReader(is, "GB18030");  

 這里可以看到,我們采用了GB18030編碼讀取外部數(shù)據(jù),通過(guò)查看streamReader的encoding可以印證:

1.assertEquals("GB18030", streamReader.getEncoding());    

正是由于上面我們?yōu)橥獠抠Y源指定了正確的編碼,當(dāng)它轉(zhuǎn)成char數(shù)組時(shí)才能正確地進(jìn)行解碼(GB18030 -> unicode)

1.1.  char[] chars = new char[is.available()];       

2.2.  streamReader.read(chars, 0, is.available());    

但我們經(jīng)常寫的代碼就像下面這樣:

1.1.  InputStream is = new FileInputStream("res/input2.data");       

2.2.  InputStreamReader streamReader = new InputStreamReader(is);    

這時(shí)候InputStreamReader采用什么編碼方式讀取外部資源呢?Unicode?不是,這時(shí)候采用的編碼方式是JVM的默認(rèn)字符集,這個(gè)默認(rèn)字符集在虛擬機(jī)啟動(dòng)時(shí)決定,通常根據(jù)語(yǔ)言環(huán)境和底層操作系統(tǒng)的 charset 來(lái)確定??梢酝ㄟ^(guò)以下方式得到JVM的默認(rèn)字符集:

1.1.  Charset.defaultCharset();      

為什么要這樣?因?yàn)槲覀儚耐獠抠Y源讀取數(shù)據(jù),而外部資源的編碼方式通常跟操作系統(tǒng)所使用的字符集一樣,所以采用這種默認(rèn)方式是可以理解的。

好吧,那么我通過(guò)我的IDE Ideas創(chuàng)建了一個(gè)文件,并以JVM默認(rèn)的編碼方式從這個(gè)文件讀取數(shù)據(jù),但讀出來(lái)的數(shù)據(jù)竟然是亂碼。為何?呵呵,其實(shí)是因?yàn)橥ㄟ^(guò)Ideas創(chuàng)建的文件是以u(píng)tf-8編碼的。要得到一個(gè)JVM默認(rèn)編碼的文件,通過(guò)手工創(chuàng)建一個(gè)txt文件試試吧。

2.字符串和字節(jié)數(shù)組的相互轉(zhuǎn)換

我們通常通過(guò)以下代碼把字符串轉(zhuǎn)換成字節(jié)數(shù)組:

1.1.  "string".getBytes();    

但你是否注意過(guò)這個(gè)轉(zhuǎn)換采用的編碼呢?其實(shí)上面這句代碼跟下面這句是等價(jià)的:

1.1.  "string".getBytes(Charset.defaultCharset());    

也就是說(shuō)它根據(jù)JVM的默認(rèn)編碼(而不是你可能以為的unicode)把字符串轉(zhuǎn)換成一個(gè)字節(jié)數(shù)組。

反之,如何從字節(jié)數(shù)組創(chuàng)建一個(gè)字符串呢?

1.1.  new String("string".getBytes());    

同樣,這個(gè)方法使用平臺(tái)的默認(rèn)字符集解碼字節(jié)的指定數(shù)組(這里的解碼指從一種字符集到unicode)。

字符串編碼迷思:

1.1.  new String(input.getBytes("ISO-8859-1"), "GB18030")    

上面這段代碼代表什么?有人會(huì)說(shuō): “把input字符串從ISO-8859-1編碼方式轉(zhuǎn)換成GB18030編碼方式”。如果這種說(shuō)法正確,那么又如何解釋我們剛提到的java字符串都采用unicode編碼呢?

這種說(shuō)法不僅是欠妥的,而且是大錯(cuò)特錯(cuò)的,讓我們一一來(lái)分析,其實(shí)事實(shí)是這樣的:我們本應(yīng)該用GB18030的編碼來(lái)讀取數(shù)據(jù)并解碼成字符串,但結(jié)果卻采用了ISO-8859-1的編碼,導(dǎo)致生成一個(gè)錯(cuò)誤的字符串。要恢復(fù),就要先把字符串恢復(fù)成原始字節(jié)數(shù)組,然后通過(guò)正確的編碼GB18030再次解碼成字符串(即把以GB18030編碼的數(shù)據(jù)轉(zhuǎn)成unicode的字符串)。注意,字符串永遠(yuǎn)都是unicode編碼的。

但編碼轉(zhuǎn)換并不是負(fù)負(fù)得正那么簡(jiǎn)單,這里我們之所以可以正確地轉(zhuǎn)換回來(lái),是因?yàn)?ISO8859-1 是單字節(jié)編碼,所以每個(gè)字節(jié)被按照原樣 轉(zhuǎn)換為 String ,也就是說(shuō),雖然這是一個(gè)錯(cuò)誤的轉(zhuǎn)換,但編碼沒(méi)有改變,所以我們?nèi)匀挥袡C(jī)會(huì)把編碼轉(zhuǎn)換回來(lái)! 

總結(jié): 

所以,我們?cè)谔幚韏ava的編碼問(wèn)題時(shí),要分清楚三個(gè)概念:Java采用的編碼:unicode,JVM平臺(tái)默認(rèn)字符集和外部資源的編碼。

程序示例:

public static void main(String args[])  
  {  
    System.out.println("default charset : "+Charset.defaultCharset());  
    String str = "abc你好";//string with UTF-8 charset  
    byte[] bytes = str.getBytes(Charset.forName("UTF-8"));//convert to byte array with UTF-8 encode  
    for (byte b : bytes)  
    {  
      System.out.print(b + " ");  
    }  
    System.out.println();  
    try  
    {  
      String str1 = new String(bytes, "UTF-8");//to UTF-8 string  
      String str2 = new String(bytes, "ISO-8859-1");//to ISO-8859-1 string  
      String str3 = new String(bytes, "GBK");//to GBK string  
      System.out.println(str1);//abc你好  
      System.out.println(str2);//abc??????  
      System.out.println(str3);//abc浣犲ソ  
      System.out.println();  
      byte[] bytes2 = str2.getBytes(Charset.forName("ISO-8859-1"));  
      for (byte b : bytes2)  
      {  
        System.out.print(b + " ");  
      }  
      System.out.println();  
      String str22 = new String(bytes2, "UTF-8");  
      System.out.println(str22);//abc你好  
      System.out.println();  
      byte[] bytes3 = str3.getBytes(Charset.forName("GBK"));  
      for (byte b : bytes3)  
      {  
        System.out.print(b + " ");  
      }  
      System.out.println();  
      String str33 = new String(bytes3, "UTF-8");  
      System.out.println(str33);//abc你好  
    } catch (UnsupportedEncodingException e)  
    {  
      e.printStackTrace();  
    }  
  } 

運(yùn)行結(jié)果:

default charset : GBK    
 98 99 -28 -67 -96 -27 -91 -67     
abc你好    
abc??????    
abc浣犲ソ        

 98 99 -28 -67 -96 -27 -91 -67     
abc你好    
7 98 99 -28 -67 -96 -27 -91 -67     
abc你好   

總結(jié)

以上所述是小編給大家介紹的Java字符編碼簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java實(shí)現(xiàn)把兩個(gè)數(shù)組合并為一個(gè)的方法總結(jié)

    Java實(shí)現(xiàn)把兩個(gè)數(shù)組合并為一個(gè)的方法總結(jié)

    這篇文章主要介紹了Java實(shí)現(xiàn)把兩個(gè)數(shù)組合并為一個(gè)的方法,結(jié)合實(shí)例形式總結(jié)分析了java常用的四種數(shù)組合并操作技巧,需要的朋友可以參考下
    2017-12-12
  • 詳解SpringBoot實(shí)現(xiàn)ApplicationEvent事件的監(jiān)聽(tīng)與發(fā)布

    詳解SpringBoot實(shí)現(xiàn)ApplicationEvent事件的監(jiān)聽(tīng)與發(fā)布

    這篇文章主要為大家詳細(xì)介紹了SpringBoot如何實(shí)現(xiàn)ApplicationEvent事件的監(jiān)聽(tīng)與發(fā)布,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-03-03
  • Spring中的AutowireCandidateResolver的具體使用詳解

    Spring中的AutowireCandidateResolver的具體使用詳解

    這篇文章主要介紹了Spring中的AutowireCandidateResolver的具體使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • 詳解Java的Spring框架中bean的注入集合

    詳解Java的Spring框架中bean的注入集合

    這篇文章主要介紹了詳解Java的Spring框架中bean的注入集合,Spring是Java的SSH三大web開(kāi)發(fā)框架之一,需要的朋友可以參考下
    2015-12-12
  • idea中cherry pick的用法

    idea中cherry pick的用法

    Cherry-Pick可以將一個(gè)分支的某些commit,合并到另一個(gè)分支,本文給大家分享idea中cherry pick的用法,感興趣的朋友跟隨小編一起看看吧
    2023-08-08
  • Java 線程池的作用以及該如何使用

    Java 線程池的作用以及該如何使用

    這篇文章主要介紹了Java 線程池的作用以及該如何使用,幫助大家更好的理解和學(xué)習(xí)Java的相關(guān)知識(shí),感興趣的朋友可以了解下
    2021-01-01
  • java如何利用NIO壓縮文件或文件夾

    java如何利用NIO壓縮文件或文件夾

    這篇文章主要介紹了java如何利用NIO壓縮文件或文件夾問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • idea使用Mybatis逆向工程插件詳情

    idea使用Mybatis逆向工程插件詳情

    這篇文章主要介紹了idea使用Mybatis逆向工程插件詳情,首先使用mybatis連接數(shù)據(jù)庫(kù)接著添加連接的mysql的信息,測(cè)試鏈接等過(guò)程,更多過(guò)程了解請(qǐng)參考下面文章的詳細(xì)內(nèi)容
    2022-01-01
  • 詳解一個(gè)簡(jiǎn)單的Servlet容器的設(shè)計(jì)與實(shí)現(xiàn)

    詳解一個(gè)簡(jiǎn)單的Servlet容器的設(shè)計(jì)與實(shí)現(xiàn)

    Servlet算是Java Web開(kāi)發(fā)請(qǐng)求鏈路調(diào)用棧中底層的一個(gè)技術(shù),而了解一個(gè)Servlet容器的實(shí)現(xiàn)有助于更好的理解JavaWeb開(kāi)發(fā),所以下面就來(lái)看看如何設(shè)計(jì)與實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Servlet容器吧
    2023-07-07
  • 淺談Java設(shè)計(jì)模式之原型模式知識(shí)總結(jié)

    淺談Java設(shè)計(jì)模式之原型模式知識(shí)總結(jié)

    Java原型模式主要用于創(chuàng)建重復(fù)的對(duì)象,同時(shí)又能保證性能,這篇文章就帶大家仔細(xì)了解一下原型模式的知識(shí),對(duì)正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05

最新評(píng)論