Java的编码解码
Java的編碼解碼
前言:
介紹編碼和解碼之前,我們先了解一下我們的計算機,計算機中存儲數(shù)據(jù)的具體單位是存儲單元,
一個最小的信息單元就是“位”(bit),一"位"只能表示0和1中的一個,即一個二進制位;
“字節(jié)”(Byte):是由相連8個位組成的信息存儲單位,它是目前計算機最基本的存儲單位,一個字節(jié)通常可以存儲一個字符(如字母、數(shù)字等)。只有字節(jié)才有地址的概念。對一種計算機的存儲設(shè)備以字節(jié)為單位賦予的地址稱為字節(jié)編址;也是目前計算機最基本的存儲單元編址;
java的基本數(shù)據(jù)類型:
| byte | 8位 | 最大存儲數(shù)據(jù)量是255,存放的數(shù)據(jù)范圍是-128~127之間 |
| short | 16位 | 最大數(shù)據(jù)存儲量是65536,數(shù)據(jù)范圍是-32768~32767之間 |
| int | 32位 | 最大數(shù)據(jù)存儲容量是2的32次方減1,數(shù)據(jù)范圍是負的2的31次方到正的2的31次方減1 |
| long | 64位 | 最大數(shù)據(jù)存儲容量是2的64次方減1,數(shù)據(jù)范圍為負的2的63次方到正的2的63次方減1 |
| float | 32位 | 數(shù)據(jù)范圍在3.4e-45~1.4e38,直接賦值時必須在數(shù)字后加上f或F |
| double | 64位 | 數(shù)據(jù)范圍在4.9e-324~1.8e308,賦值時可以加d或D也可以不加 |
| boolean | 只有true和false兩個取值 | |
| char | 16位 | 存儲Unicode碼,用單引號賦值 |
進入今天的正題:
首先要知道編碼和解碼是char和byte兩個數(shù)據(jù)類型之間轉(zhuǎn)換中產(chǎn)生的;
為什么要編碼?
最直接的回答就是防止我們的中文和一些特殊字符出現(xiàn)亂碼的現(xiàn)象;
詳細點講就是計算機只能識別0和1兩個數(shù)字,所有的符號和文字都必須經(jīng)過轉(zhuǎn)換編碼才能“翻譯”成我們計算機認識的“語言”,相反也是,我們要想顯示出我們能讀懂的“語言”也必須要進行相應(yīng)的解碼才能從計算機中顯示出我們能看懂的文字;
總的來說編碼的原因有:
如何編碼和解碼呢?
那就是通過一種特定的編碼格式轉(zhuǎn)換,其實現(xiàn)在有很多中的編碼格式,只要讓計算機按照規(guī)定的編碼格式進行轉(zhuǎn)化,就可以顯示成我們自己的字符。那現(xiàn)在就介紹一下目前最常見的一些編碼格式;
首先我們要知道編碼和編碼格式是有區(qū)別的?
編碼就是一個編號(數(shù)字)到字符的一種映射關(guān)系,是一種一對一的映射關(guān)系。Unicode和ASCII 就是屬于兩種編碼,但這兩種編碼能編碼的范圍不同,Unicode 能編碼的范圍要更大一些,幾乎能覆蓋現(xiàn)存的所有字符(Java語言使用的就是該碼表);
ASCII碼
在計算機種中,1 字節(jié)對應(yīng) 8 位二進制數(shù),而每位二進制數(shù)有 0、1 兩種狀態(tài),因此 1 字節(jié)可以組合出 256 種狀態(tài)。如果這 256 中狀態(tài)每一個都對應(yīng)一個符號,就能通過 1 字節(jié)的數(shù)據(jù)表示 256 個字符。美國人于是就制定了一套編碼(其實就是個字典),描述英語中的字符和這 8 位二進制數(shù)的對應(yīng)關(guān)系,這被稱為 ASCII 碼。
ASCII 碼一共定義了 128 個字符,例如大寫的字母 A 是 65(這是十進制數(shù),對應(yīng)二進制是0100 0001)。這 128 個字符只使用了 8 位二進制數(shù)中的后面 7 位,最前面的一位統(tǒng)一規(guī)定為 0。
Unicode
Unicode 只是一個字符集,規(guī)定了符合對應(yīng)的二進制代碼,至于這個二進制代碼如何存儲則沒有任何規(guī)定。它的想法很簡單,就是為每個字符規(guī)定一個用來表示該字符的數(shù)字,僅此而已。
Unicode編碼方案
之前提到,Unicode 沒有規(guī)定字符對應(yīng)的二進制碼如何存儲。以漢字“漢”為例,它的 Unicode 碼點是 0x6c49,對應(yīng)的二進制數(shù)是 110110001001001,二進制數(shù)有 15 位,這也就說明了它至少需要 2 個字節(jié)來表示。可以想象,在 Unicode 字典中往后的字符可能就需要 3 個字節(jié)或者 4 個字節(jié),甚至更多字節(jié)來表示了。
這就導(dǎo)致了一些問題,計算機怎么知道你這個 2 個字節(jié)表示的是一個字符,而不是分別表示兩個字符呢?這里我們可能會想到,那就取個最大的,假如 Unicode 中最大的字符用 4 字節(jié)就可以表示了,那么我們就將所有的字符都用 4 個字節(jié)來表示,不夠的就往前面補 0。這樣確實可以解決編碼問題,但是卻造成了空間的極大浪費,如果是一個英文文檔,那文件大小就大出了 3 倍,這顯然是無法接受的。
于是,為了較好的解決 Unicode 的編碼問題, UTF-8 和 UTF-16 兩種當(dāng)前比較流行的編碼方式誕生了。當(dāng)然還有一個 UTF-32 的編碼方式,也就是上述那種定長編碼,字符統(tǒng)一使用 4 個字節(jié),雖然看似方便,但是卻不如另外兩種編碼方式使用廣泛。
對于編碼格式目前最常見的是UTF-8、GBK,它們都是用來序列化或存儲 Unicode 編碼的數(shù)據(jù)的,但是分別是2中不同的格式,他們都是 Unicode 的實現(xiàn)方式,當(dāng)然也還有很多,這里就先介紹這兩種啦。
-
GBK
全稱叫《漢字內(nèi)碼擴展規(guī)范》,是國家技術(shù)監(jiān)督局為 windows95 所制定的新的漢字內(nèi)碼規(guī)范,它的出現(xiàn)是為了擴展 GB2312,加入更多的漢字,它的編碼范圍是 8140~FEFE(去掉 XX7F)總共有 23940 個碼位,它能表示 21003 個漢字,它的編碼是和 GB2312 兼容的,也就是說用 GB2312 編碼的漢字可以用 GBK 來解碼,并且不會有亂碼。
-
UTF-8
UTF-8 采用了一種變長技術(shù),每個編碼區(qū)域有不同的字碼長度。不同類型的字符可以是由 1~6 個字節(jié)組成。
編碼規(guī)則:
使用utf-8進行編碼解碼
“漢”的 Unicode 碼點是 0x6c49(110 1100 0100 1001),通過上面的對照表可以發(fā)現(xiàn),0x0000 6c49 位于第三行的范圍,那么得出其格式為 1110xxxx 10xxxxxx 10xxxxxx。接著,從“漢”的二進制數(shù)最后一位開始,從后向前依次填充對應(yīng)格式中的 x,多出的 x 用 0 補上。這樣,就得到了“漢”的 UTF-8 編碼為 11100110 10110001 10001001,轉(zhuǎn)換成十六進制就是 0xE6 0xB7 0x89。
解碼的過程也十分簡單:如果一個字節(jié)的第一位是 0 ,則說明這個字節(jié)對應(yīng)一個字符;如果一個字節(jié)的第一位1,那么連續(xù)有多少個 1,就表示該字符占用多少個字節(jié)。
java中編解碼場景
流讀取文件,其中就存在著字符與字節(jié)之間的轉(zhuǎn)換; InputStreamReader 類就是關(guān)聯(lián)字節(jié)到字符的橋梁,它負責(zé)在 I/O 過程中處理讀取字節(jié)到字符的轉(zhuǎn)換;
// 創(chuàng)建指定字符集的 InputStreamReader InputStreamReader(InputStream in, String CharsetName) // 創(chuàng)建使用指定字符集的 OutputStreamWriter OutputStreamWriter(OutputStream out, String CharsetName)處理字符串編碼問題
//獲取utf-8對應(yīng)的的字符集 Charset charset = Charset.forName("utf-8"); //將字符串通過utf-8進行編碼轉(zhuǎn)化成字節(jié) byte[] bytes = str.getBytes(charset); //再將字節(jié)根據(jù)相同的編碼格式進行解碼 String string = new String(bytes, "utf-8"); System.out.println(string);處理請求參數(shù)傳遞編碼問題
URLEncoder.encode(strUri, "UTF-8"); URLDecoder.decode(strUri, "UTF-8");值得一看的相關(guān)文章:https://blog.csdn.net/troyaninpc/article/details/79476751
下一篇:session會話理解
總結(jié)
- 上一篇: 使用iText处理pdf文件的入门级教程
- 下一篇: 富文本编辑器在Java中使用