新聞中心
[[373184]]

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:域名注冊(cè)、雅安服務(wù)器托管、營(yíng)銷軟件、網(wǎng)站建設(shè)、鎮(zhèn)巴網(wǎng)站維護(hù)、網(wǎng)站推廣。
前言
編碼的轉(zhuǎn)換通常在IO機(jī)制中使用,一個(gè)好的編碼可以為我們節(jié)省很多空間,在某種程度上提高我們應(yīng)用的效率。由于之前就知道String中的轉(zhuǎn)換方式,還有一些工具類,因此今天就好好的整理一下java中jdk提供的幾種轉(zhuǎn)換方式,希望對(duì)你有幫助。
一、編碼轉(zhuǎn)換原理
1、為什么需要編碼
我們知道計(jì)算機(jī)存儲(chǔ)信息的最小單位是一個(gè)字節(jié)8位,能夠表示256個(gè)字符。這對(duì)于早起的英文來(lái)說(shuō)足夠了。即使是加上一些常見符號(hào)也足夠。于是在1965年美國(guó)制定了ASCII編碼,主要用于英語(yǔ)和西歐語(yǔ)言,一開始128個(gè),后來(lái)加到了256。
后來(lái)隨著時(shí)間的發(fā)展,中國(guó)、日本等國(guó)的計(jì)算機(jī)也開始蓬勃發(fā)展,于是計(jì)算機(jī)不僅僅要存儲(chǔ)英文了,也開始存儲(chǔ)中文。但是中文我們都知道幾萬(wàn)個(gè)太多了,一個(gè)字節(jié)肯定放不下。怎么辦呢?一個(gè)字節(jié)表示不下,那就多用幾個(gè)字節(jié)就好了。這樣不僅可以表示漢字,還可以避免了與ASCII編碼的沖突。這幾個(gè)字節(jié)在存儲(chǔ)的時(shí)候再轉(zhuǎn)化為bit,完美!劃重點(diǎn)哈,編碼解決的就是字節(jié)和字符之間的轉(zhuǎn)化問(wèn)題。
2、編碼方式
既然是編碼,那些大佬早就考慮到了這些問(wèn)題,并提拱了多種編碼方式,常見的有 ASCII、ISO-8859-1、GB2312、GBK、UTF-8、UTF-16 等。它們規(guī)定了轉(zhuǎn)化的規(guī)則,按照這個(gè)規(guī)則就可以讓計(jì)算機(jī)正確的表示我們的字符。
像GB2312、GBK、UTF-8、UTF-16等很多種方式都可以表示漢字,他們有什么區(qū)別呢?
(1)GB2312
它是雙字節(jié)編碼,總的編碼范圍是 A1-F7,其中從 A1-A9 是符號(hào)區(qū),總共包含 682 個(gè)符號(hào),從 B0-F7 是漢字區(qū),包含 6763 個(gè)漢字。這個(gè)是中國(guó)1981年搞出來(lái)的。這種編碼是一個(gè)漢字兩個(gè)字節(jié)。
(2)GBK
它的編碼范圍是 8140~FEFE(去掉 XX7F)總共有 23940 個(gè)碼位,它能表示 21003 個(gè)漢字。這個(gè)是中國(guó)在1995年搞出來(lái)的,主要是用于GB2312編碼的補(bǔ)充。這種編碼依然是一個(gè)漢字兩個(gè)字節(jié)。
(3)Unicode
上面看到,中國(guó)可以做出了一個(gè)編碼,日本也可以做出來(lái)一個(gè)編碼,時(shí)間久了每個(gè)國(guó)家都有著自己的一套編碼,就不可避免的造成沖突。于是Unicode出來(lái)了,把所有語(yǔ)言統(tǒng)一起來(lái)合成一個(gè)規(guī)則。這種編碼是定長(zhǎng)的字節(jié)數(shù)。
(4)UTF8
既然Unicode是定長(zhǎng)的字節(jié)數(shù),那么存儲(chǔ)一個(gè)復(fù)雜的漢字可能需要三個(gè)字節(jié),但是為了保證是2的冪數(shù)集,就會(huì)自動(dòng)擴(kuò)充為4個(gè)字節(jié),別看著一個(gè)字節(jié)之差,存儲(chǔ)的字?jǐn)?shù)多了就會(huì)極大的浪費(fèi)空間。是于是而 UTF-8 采用了一種變長(zhǎng)技術(shù),每個(gè)編碼區(qū)域有不同的字碼長(zhǎng)度。不同類型的字符可以是由 1~6 個(gè)字節(jié)組成。
以上這些編碼方式會(huì)為每一個(gè)漢字或者是字母建立一個(gè)編碼庫(kù),在編碼的時(shí)候字母和編碼一一對(duì)應(yīng)。
3、為什么會(huì)出現(xiàn)亂碼?
這個(gè)問(wèn)題就是因?yàn)榫幋a和解碼是采用了不同的或者是不兼容的編碼方案。比如一個(gè)用UTF-8編碼的后的字符。再用GBK去解碼,由于兩個(gè)字符集的編碼庫(kù)不一樣。同一個(gè)漢字在兩個(gè)編碼庫(kù)的位置也不一樣。于是就出現(xiàn)了亂碼。
4、java如何解決亂碼問(wèn)題?
這個(gè)問(wèn)題其實(shí)就是java中如何使用編碼規(guī)則,因?yàn)槭褂煤昧司幋a規(guī)則。才可以很好地解決亂碼問(wèn)題。
(1)IO流
編碼的目的上面已經(jīng)說(shuō)了,主要是字節(jié)和字符之間的轉(zhuǎn)化。既然涉及到字節(jié)和字符很容易我們就能想到j(luò)ava中的IO流。也就是說(shuō)java中編碼的轉(zhuǎn)換其實(shí)就是IO流中的類來(lái)實(shí)現(xiàn)的。
最核心的就是上面幾個(gè)類,當(dāng)然這里只是給出了輸入的一部分,還有一些輸出的類。
(2)String
String類中也提供了一些轉(zhuǎn)碼的方法。下面我們會(huì)通過(guò)實(shí)例來(lái)說(shuō)明。為什么String可以實(shí)現(xiàn)呢?這是因?yàn)镾tring底層保存的其實(shí)就是一個(gè)一個(gè)字節(jié),而且String還有方法直接轉(zhuǎn)化為字符。所以String肯定也能實(shí)現(xiàn)。
(3)Charset
這個(gè)Charset是javaNIO中的一個(gè)類,整個(gè)流程就是讀取數(shù)據(jù),然后轉(zhuǎn)化為byte,也就是字符。然后重新編碼成字符就OK了。
下面我們使用代碼來(lái)實(shí)現(xiàn)一下:
二、代碼實(shí)現(xiàn)
1、IO流
首先是IO流實(shí)現(xiàn),這種通過(guò)輸入輸出流可以直接的指定編碼規(guī)則。
- public void convertionFile() 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肯定會(huì)出現(xiàn)錯(cuò)誤
- }
2、String
使用string是最方便的,代碼也比較簡(jiǎn)潔,適用于字符串的編碼。
- public void convertionString() throws UnsupportedEncodingException {
- String s = "愚公要移山,碼農(nóng)飛上天";
- // 正常情況下轉(zhuǎn)碼的過(guò)程
- byte[] b = s.getBytes("gbk");// 編碼
- String sa = new String(b, "gbk");// 解碼
- System.out.println(sa);
- // 錯(cuò)誤狀態(tài)下轉(zhuǎn)碼的過(guò)程
- b = sa.getBytes("utf-8");// 編碼使用utf-8
- sa = new String(b, "gbk");// 解碼使用gbk
- System.err.println(sa);
- }
- //控制臺(tái)輸出:
- //愚公要移山,碼農(nóng)飛上天
- //鎰氬叕瑕佺Щ灞憋紝鐮佸啘椋炰笂澶?
3、Charset
- public void convertionCharset() throws IOException {
- Charset charset = StandardCharsets.UTF_8;
- // 從字符集中創(chuàng)建相應(yīng)的編碼和解碼器
- CharsetEncoder encoder = charset.newEncoder();
- CharsetDecoder decoder = charset.newDecoder();
- // 構(gòu)造一個(gè)buffer
- CharBuffer charBuffer = CharBuffer.allocate(64);
- charBuffer.put('A');
- charBuffer.flip();
- // 將字符序列轉(zhuǎn)換成字節(jié)序列
- ByteBuffer bb = encoder.encode(charBuffer);
- // 將字節(jié)序列轉(zhuǎn)換成字符序列
- bb.flip();
- CharBuffer cb = decoder.decode(bb);
- }
以上就是三種基本的實(shí)現(xiàn)方式,當(dāng)然還有一些其他的,比如Spring中提供的編碼轉(zhuǎn)換工具等等。在這里就不說(shuō)了,因?yàn)榧夹g(shù)太多,實(shí)現(xiàn)的方式也太多,我們就看這幾種即可。
本文轉(zhuǎn)載自微信公眾號(hào)「愚公要移山」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系愚公要移山公眾號(hào)。
當(dāng)前題目:你了解Java中的幾種編碼方式?解決亂碼問(wèn)題可能并不麻煩
網(wǎng)站URL:http://www.fisionsoft.com.cn/article/cdheood.html


咨詢
建站咨詢
