爲何須要編碼?java
計算機中最小的存儲單位是字節(byte),一個字節所能表示的字符數又有限,1byte=8bit,一個字節最多也只能表示255個字符,而世界上的語種又多,都有各類不一樣的字符,沒法用一個byte表示,因此java中的char表示字符就是來解決這種編碼問題的,一個char佔兩個字節,因此從char到最小單位byte之間必須通過編碼,反之爲解碼。數組
其實,編碼解碼就是完成的翻譯過程(「翻譯」很容易理解吧),各類編碼方式就是一部部字典。瀏覽器
一、ASCII碼網絡
全稱爲American Standard Code for Information Interchange,美國信息交換標準代碼,這是世界上最通用的單字節編碼系統,主要用來顯示現代英語及其餘西歐語言。函數
ASCII碼用7位表示,只能表示128個字符,0~31表示控制字符如回車、退格、刪除等;32~126表示打印字符便可以經過鍵盤輸入而且能顯示出來的字符,工具
其中48~57爲0到9十個阿拉伯數字,65~90爲26個大寫英文字母,97~122號爲26個小寫英文字母,其他爲一些標點符號、運算符號等,具體能夠參考ASCII標準表。編碼
二、ISO-8859-1url
該編碼是在ASCII編碼的基礎上擴展出來的,但它仍然是單字節編碼,總共只能表示256個字符。spa
既然ASCII只能表示128個字符,顯示是不能徹底表示完的,因此ISO-8859-1擴展了ASCII編碼,在ASCII編碼之上又增長了西歐語言、希臘語、泰語、阿拉伯語、希伯來語對應的文字符號,它是向下兼容ASCII編碼的。翻譯
三、GB2312
GB2312的全稱是《信息技術 中文編碼字符集》,它是雙字節編碼,編碼範圍是A1-F7,其中A1-A9是符號區,總共包含682個符號;B0-F7是漢字區,包含6763個漢字。
全稱爲信息交換用漢字編碼字符集,是中國於1980年發佈,主要用於計算機系統中的漢字處理。GB2312主要收錄了6763個漢字、682個符號。
GB2312覆蓋了漢字的大部分使用率,但不能處理像古漢語等特殊的罕用字,因此後來出現了像GBK、GB18030這種編碼。
四、GBK
GBK的全稱是《漢字內碼擴展規範》,它的出現是爲了擴展GB2312,它的編碼範圍是8140-FEFE(去掉XX7F),總共有23940個碼位,能表示21003個漢字,它的編碼是和GB2312兼容的
GBK,全稱爲Chinese Internal Code Specification,即漢字內碼擴展規範,於1995年制定。它主要是擴展了GB2312,在它的基礎上又加了更多的漢字,它一共收錄了21003個漢字。
GBK是向下兼容GB2312編碼的,也就是說GB2312編碼的漢字能夠用GBK正常解碼不會出現亂碼,但用GBK編碼的漢字用GB2312解碼就不必定了。
五、GB18030
GB18030全稱漢字內碼擴展規範,是如今最新的內碼字集於2000年發佈,並於2001年強制執行,包含了中國大部分少數民族的語言字符,收錄漢字數超過70000餘個。
它主要採用單字節、雙字節、四字節對字符編碼,它是向下兼容GB2312和GBK的,雖然是我國的強制使用標準,但在實際生產中不多用到,用得最多的反而是GBK和GB2312。
6.UNICODE
爲了本身的語言能在計算機中正常顯示,每一個國家和地區都有各自的編碼,因此編碼多了誰也不認識對方的編碼,這時候ISO組織就提出了一種新的編碼叫UNICODE編碼讓全球的文化、字符、符號都能支持。UNICODE在制定時計算機容量已不是問題,因此設計成了固定兩個字節,全部的字符都用16位表示,包括以前只佔8位的英文字符等,因此會形成空間的浪費,UNICODE在很長的一段時間內都沒有獲得推廣應用。
七、UTF-16
UTF-16的出現是ISO想要建立一個全新的超語言字典,世界上全部的語言均可以經過這個字典來相互翻譯,可想而知,這個字典是多麼的複雜、龐大。UTF-16用兩個字節來表示Unicode的轉化格式(兩個字節就是16個bit,因此要UTF-16),採用的是定長的表示方法,即任何字符均可以用兩個字節表示。這樣表示字符就是變得的很是方便。可是,也有一個缺陷,就是很大一部分的字符用一個字節就能夠表示了,UTF-16卻用兩個字節,有些浪費存儲空間。因此有另外一個編碼方式就出現了,也就是UTF-8。
UTF-16是UNICODE的具體實現,16即16位,UTF-16便是這個來由,定義了UNICODE字符在計算機中的存儲方式,UTF-16一樣使用了兩個字節來表示任何字符,這樣使得操做字符串很是高效,這也是java把UTF-16做爲字符在內存中存儲的格式的重要緣由。
UTF-16適合在磁盤與內存之間使用,字符和字節的相互轉換會更加簡單和高效,但不適合在網絡上傳輸,由於網絡傳輸可能會損壞字節流。
八、UTF-8
UTF-8採用了一種變長技術,每一個編碼區域有不一樣的字碼長度,不一樣類型的字符能夠由1-6個字節組成。
UTF-8的編碼規則以下:
1) 若是是1個字節,最高位爲0,則表示這是1個ASCII字符。可見,全部ASCII編碼已是UTF-8了
2) 若是是1個字節,以11開頭,則連續的1的個數暗示這個字符的字節數,例如:110xxxxx表明它是雙字節UTF-8字符的首字節
3) 若是是1個字節,以10開始,表示它不是首字節,則須要向前查找才能獲得當前字符的首字節。
雖然UTF-16很高效,但也是UNICODE最大的壞處,使得全部單字節字符必定要佔兩個字節,存儲空間放大了一倍,這明顯消耗了資源,不符合如今互聯網高速發展的現狀。因此有了UTF-8,它是UNICODE的一種可變長度字符編碼的實現,它可使用1~6個定長字節來編碼UNICODE字符。
UTF-8對ASCII字符使用單字節存儲,單個字符損壞也不會影響後面的字符,因此UTF-8很是適合在網絡上面傳統,也是如今使用最普遍的編碼之一。
若是要表示中文,UTF-8編碼效率要大於GBK,小於UTF-16,因此它也是除了GBK以外最理想的編碼方式。
=======================================================================================
本文主要包括如下幾個方面:編碼基本知識,java,系統軟件,url,工具軟件等。
在下面的描述中,將以"中文"兩個字爲例,經查表能夠知道其GB2312編碼是"d6d0 cec4",Unicode編碼爲"4e2d 6587",UTF編碼就是"e4b8ad e69687"。注意,這兩個字沒有iso8859-1編碼,但能夠用iso8859-1編碼來"表示"。
2. 編碼基本知識
最先的編碼是iso8859-1,和ascii編碼類似。但爲了方便表示各類各樣的語言,逐漸出現了不少標準編碼,重要的有以下幾個。
2.1. iso8859-1
屬於單字節編碼,最多能表示的字符範圍是0-255,應用於英文系列。好比,字母a的編碼爲0x61=97。
很明顯,iso8859-1編碼表示的字符範圍很窄,沒法表示中文字符。可是,因爲是單字節編碼,和計算機最基礎的表示單位一致,因此不少時候,仍舊使用iso8859-1編碼來表示。並且在不少協議上,默認使用該編碼。好比,雖然"中文"兩個字不存在iso8859-1編碼,以gb2312編碼爲例,應該是"d6d0 cec4"兩個字符,使用iso8859-1編碼的時候則將它拆開爲4個字節來表示:"d6 d0 ce c4"(事實上,在進行存儲的時候,也是以字節爲單位處理的)。而若是是UTF編碼,則是6個字節"e4 b8 ad e6 96 87"。很明顯,這種表示方法還須要以另外一種編碼爲基礎。
2.2. GB2312/GBK
這就是漢子的國標碼,專門用來表示漢字,是雙字節編碼,而英文字母和iso8859-1一致(兼容iso8859-1編碼)。其中gbk編碼可以用來同時表示繁體字和簡體字,而gb2312只能表示簡體字,gbk是兼容gb2312編碼的。
2.3. unicode
這是最統一的編碼,能夠用來表示全部語言的字符,並且是定長雙字節(也有四字節的)編碼,包括英文字母在內。因此能夠說它是不兼容iso8859-1編碼的,也不兼容任何編碼。不過,相對於iso8859-1編碼來講,uniocode編碼只是在前面增長了一個0字節,好比字母a爲"00 61"。
須要說明的是,定長編碼便於計算機處理(注意GB2312/GBK不是定長編碼),而unicode又能夠用來表示全部字符,因此在不少軟件內部是使用unicode編碼來處理的,好比java。
2.4. UTF
考慮到unicode編碼不兼容iso8859-1編碼,並且容易佔用更多的空間:由於對於英文字母,unicode也須要兩個字節來表示。因此unicode不便於傳輸和存儲。所以而產生了utf編碼,utf編碼兼容iso8859-1編碼,同時也能夠用來表示全部語言的字符,不過,utf編碼是不定長編碼,每個字符的長度從1-6個字節不等。另外,utf編碼自帶簡單的校驗功能。通常來說,英文字母都是用一個字節表示,而漢字使用三個字節。
注意,雖說utf是爲了使用更少的空間而使用的,但那只是相對於unicode編碼來講,若是已經知道是漢字,則使用GB2312/GBK無疑是最節省的。不過另外一方面,值得說明的是,雖然utf編碼對漢字使用3個字節,但即便對於漢字網頁,utf編碼也會比unicode編碼節省,由於網頁中包含了不少的英文字符。
3. java對字符的處理
在java應用軟件中,會有多處涉及到字符集編碼,有些地方須要進行正確的設置,有些地方須要進行必定程度的處理。
3.1. getBytes(charset)
這是java字符串處理的一個標準函數,其做用是將字符串所表示的字符按照charset編碼,並以字節方式表示。注意字符串在java內存中老是按unicode編碼存儲的。好比"中文",正常狀況下(即沒有錯誤的時候)存儲爲"4e2d 6587",若是charset爲"gbk",則被編碼爲"d6d0 cec4",而後返回字節"d6 d0 ce c4"。若是charset爲"utf8"則最後是"e4 b8 ad e6 96 87"。若是是"iso8859-1",則因爲沒法編碼,最後返回 "3f 3f"(兩個問號)。
3.2. new String(charset)
這是java字符串處理的另外一個標準函數,和上一個函數的做用相反,將字節數組按照charset編碼進行組合識別,最後轉換爲unicode存儲。參考上述getBytes的例子,"gbk" 和"utf8"均可以得出正確的結果"4e2d 6587",但iso8859-1最後變成了"003f 003f"(兩個問號)。
由於utf8能夠用來表示/編碼全部字符,因此new String( str.getBytes( "utf8" ), "utf8" ) === str,即徹底可逆。
3.3. setCharacterEncoding()
該函數用來設置http請求或者相應的編碼。
對於request,是指提交內容的編碼,指定後能夠經過getParameter()則直接得到正確的字符串,若是不指定,則默認使用iso8859-1編碼,須要進一步處理。參見下述"表單輸入"。值得注意的是在執行setCharacterEncoding()以前,不能執行任何getParameter()。java doc上說明:This method must be called prior to reading request parameters or reading input using getReader()。並且,該指定只對POST方法有效,對GET方法無效。分析緣由,應該是在執行第一個getParameter()的時候,java將會按照編碼分析全部的提交內容,然後續的getParameter()再也不進行分析,因此setCharacterEncoding()無效。而對於GET方法提交表單是,提交的內容在URL中,一開始就已經按照編碼分析全部的提交內容,setCharacterEncoding()天然就無效。
對於response,則是指定輸出內容的編碼,同時,該設置會傳遞給瀏覽器,告訴瀏覽器輸出內容所採用的編碼。
全稱爲American Standard Code for Information Interchange,美國信息交換標準代碼,這是世界上最通用的單字節編碼系統,主要用來顯示現代英語及其餘西歐語言。
ASCII碼用7位表示,只能表示128個字符,0~31表示控制字符如回車、退格、刪除等;32~126表示打印字符便可以經過鍵盤輸入而且能顯示出來的字符,
其中48~57爲0到9十個阿拉伯數字,65~90爲26個大寫英文字母,97~122號爲26個小寫英文字母,其他爲一些標點符號、運算符號等,具體能夠參考ASCII標準表。