前言
編碼的轉換通常在IO機制中使用,一個好的編碼可以為我們節省很多空間,在某種程度上提高我們應用的效率。由於之前就知道String中的轉換方式,還有一些工具類,因此今天就好好的整理一下java中jdk提供的幾種轉換方式,希望對你有幫助。
一、編碼轉換原理
1、為什麼需要編碼
我們知道計算機存儲信息的最小單位是一個字節8位,能夠表示256個字符。這對於早起的英文來說足夠了。即使是加上一些常見符號也足夠。於是在1965年美國制定了ASCII編碼,主要用於英語和西歐語言,一開始128個,後來加到了256。
後來隨著時間的發展,中國、日本等國的計算機也開始蓬勃發展,於是計算機不僅僅要存儲英文了,也開始存儲中文。但是中文我們都知道幾萬個太多了,一個字節肯定放不下。怎麼辦呢?一個字節表示不下,那就多用幾個字節就好了。這樣不僅可以表示漢字,還可以避免了與ASCII編碼的衝突。這幾個字節在存儲的時候再轉化為bit,完美!劃重點哈,編碼解決的就是字節和字符之間的轉化問題。
2、編碼方式
既然是編碼,那些大佬早就考慮到了這些問題,並提拱了多種編碼方式,常見的有 ASCII、ISO-8859-1、GB2312、GBK、UTF-8、UTF-16 等。它們規定了轉化的規則,按照這個規則就可以讓計算機正確的表示我們的字符。
像GB2312、GBK、UTF-8、UTF-16等很多種方式都可以表示漢字,他們有什麼區別呢?
(1)GB2312
它是雙字節編碼,總的編碼範圍是 A1-F7,其中從 A1-A9 是符號區,總共包含 682 個符號,從 B0-F7 是漢字區,包含 6763 個漢字。這個是中國1981年搞出來的。這種編碼是一個漢字兩個字節。
(2)GBK
它的編碼範圍是 8140~FEFE(去掉 XX7F)總共有 23940 個碼位,它能表示 21003 個漢字。這個是中國在1995年搞出來的,主要是用於GB2312編碼的補充。這種編碼依然是一個漢字兩個字節。
(3)Unicode
上面看到,中國可以做出了一個編碼,日本也可以做出來一個編碼,時間久了每個國家都有著自己的一套編碼,就不可避免的造成衝突。於是Unicode出來了,把所有語言統一起來合成一個規則。這種編碼是定長的字節數。
(4)UTF8
既然Unicode是定長的字節數,那麼存儲一個複雜的漢字可能需要三個字節,但是為了保證是2的冪數集,就會自動擴充為4個字節,別看著一個字節之差,存儲的字數多了就會極大的浪費空間。是於是而 UTF-8 採用了一種變長技術,每個編碼區域有不同的字碼長度。不同類型的字符可以是由 1~6 個字節組成。
以上這些編碼方式會為每一個漢字或者是字母建立一個編碼庫,在編碼的時候字母和編碼一一對應。
3、為什麼會出現亂碼?
這個問題就是因為編碼和解碼是採用了不同的或者是不兼容的編碼方案。比如一個用UTF-8編碼的後的字符。再用GBK去解碼,由於兩個字符集的編碼庫不一樣。同一個漢字在兩個編碼庫的位置也不一樣。於是就出現了亂碼。
4、java如何解決亂碼問題?
這個問題其實就是java中如何使用編碼規則,因為使用好了編碼規則。才可以很好地解決亂碼問題。
(1)IO流
編碼的目的上面已經說了,主要是字節和字符之間的轉化。既然涉及到字節和字符很容易我們就能想到java中的IO流。也就是說java中編碼的轉換其實就是IO流中的類來實現的。
最核心的就是上面幾個類,當然這裡只是給出了輸入的一部分,還有一些輸出的類。
(2)String
String類中也提供了一些轉碼的方法。下面我們會通過實例來說明。為什麼String可以實現呢?這是因為String底層保存的其實就是一個一個字節,而且String還有方法直接轉化為字符。所以String肯定也能實現。
(3)Charset
這個Charset是javaNIO中的一個類,整個流程就是讀取數據,然後轉化為byte,也就是字符。然後重新編碼成字符就OK了。
下面我們使用代碼來實現一下:
二、代碼實現
1、IO流
首先是IO流實現,這種通過輸入輸出流可以直接的指定編碼規則。
publicvoidconvertionFile()throws IOException {File file = new File("./愚公要移山.txt"); FileInputStream fis = new FileInputStream(file); InputStreamReader inReader = new InputStreamReader(fis, "gbk"); FileOutputStream fos = new FileOutputStream(file); OutputStreamWriter outReader = new OutputStreamWriter(fos, "utf-8");//這種輸入gbk,輸出utf-8肯定會出現錯誤 }
2、String
使用string是最方便的,代碼也比較簡潔,適用於字符串的編碼。
publicvoidconvertionString()throws UnsupportedEncodingException {String s = "愚公要移山,碼農飛上天";// 正常情況下轉碼的過程byte[] b = s.getBytes("gbk");// 編碼 String sa = new String(b, "gbk");// 解碼 System.out.println(sa);// 錯誤狀態下轉碼的過程 b = sa.getBytes("utf-8");// 編碼使用utf-8 sa = new String(b, "gbk");// 解碼使用gbk System.err.println(sa);}//控制臺輸出://愚公要移山,碼農飛上天//鎰氬叕瑕佺Щ灞憋紝鐮佸啘椋炰笂澶?
3、Charset
publicvoidconvertionCharset()throws IOException {Charset charset = StandardCharsets.UTF_8;// 從字符集中創建相應的編碼和解碼器 CharsetEncoder encoder = charset.newEncoder(); CharsetDecoder decoder = charset.newDecoder();// 構造一個buffer CharBuffer charBuffer = CharBuffer.allocate(64); charBuffer.put('A'); charBuffer.flip();// 將字符序列轉換成字節序列 ByteBuffer bb = encoder.encode(charBuffer);// 將字節序列轉換成字符序列 bb.flip(); CharBuffer cb = decoder.decode(bb);}
以上就是三種基本的實現方式,當然還有一些其他的,比如Spring中提供的編碼轉換工具等等。在這裡就不說了,因為技術太多,實現的方式也太多,我們就看這幾種即可。