最近做項目的時候,有時會遇到中文亂碼的問題,網上查詢了很多資料,發現大多都是只講解決方案,並沒有講到為什么要使用這種方案,這種方案的原理是什么?
最典型的就是連接數據庫的URL,我們一般把它放到classpath下的db.properties中,然后盡管我們的java代碼設置了UTF-8,JSP也設置了UTF-8,數據庫也設置了UTF-8,但是插入數據到數據庫中仍然會出現中文亂碼,最后我們的解決方案是在連接數據庫的URL上加上連接使用的編碼格式UTF-8,但是我們會納悶為什么要這么做呢?
下面我們來聊下java編碼的問題,為什么要編碼,有哪些編碼,怎么編碼和解碼,為什么會有中文亂碼,怎么解決中文亂碼。
1.為什么要編碼
這個問題必須要回到計算機是如何表示我們人類能夠理解的符號的,這些符號也就是我們人類使用的語言。由於人類的語言太多,因而表示這些語言的符號太多,無法使用計算機中一個基本的存儲單元---byte來表示,因而必須要經過拆分或一些翻譯工作,才能讓計算機理解我們的語言。我們可以把計算機能夠理解的語言假定為英語,其他語言要能夠在計算機中使用必須經過一次翻譯,把它翻譯成英語。這個翻譯的過程就是 編碼。
所以總的來說,編碼的原因可以總結為:計算機中存儲信息的最小單元是一個字節,即8個bit,所以能表示的字符范圍是0-255個;人類要表示的符號太多,無法用一個字節來完全表示。
要解決這個矛盾必須要有一個新的數據結構char,從char到byte必須編碼。
2.常見的編碼
明白了各種語言需要交流,經過翻譯是必須的,那么又如何來翻譯呢?計算機中提供了多種翻譯方式,常見的右ASCII,ISO-8859-1,GB2312,GBK,UTF-8,UTF-16等。他們可以被看做字典,他們規定了轉化的規則,按照這個規則可以讓計算機正確地標識我們的字符。目前的編碼格式很多,如GB2312,GBK,UTF-8,UTF-16都可以標識一個漢字,那我們到底選擇哪種編碼格式來存儲漢字呢?這就要考慮其他因素呢,是存儲空間重要還是編碼的效率重要。
3.怎么編碼,解碼
以String為例,代碼如下:
String s="這是一段中文字符串"; byte[] b=s.getBytes("UTF-8"); String n=new String(b,"UTF-8");
編碼的用途:把我們用戶能夠認識的語言轉化為計算機能夠認識的語言,一般用在傳輸或者存儲時,也就是涉及到計算機的操作而不是針對用戶而言。
解碼:把字節碼解釋為我們用戶能夠認識的語言。
4.為什么有中文亂碼
第一種情況:使用不能識別中文的字符集來編碼,這種情況比較少見
第二種情況,使用一種字符集來編碼,卻用另一種字符集來解碼,這種比較多見,比如,java代碼采用UTF-8編碼,但是訪問數據庫的時候,數據庫采用GBK來解碼,這就會出現中文亂碼。
Charset使用
Charset charset=Charset.forName("UTF-8"); ByteBuffer byteBuffer=charset.encode(string); CharBuffer charBuffer=charset.decode(byteBuffer);
5.java中怎么編解碼
String name="I am 小明"; toHex(name.toCharArray()); <span style="font-size:18px; white-space: pre;"></span><pre name="code" class="java">try{ byte[] iso8859=name.getBytes("ISO-8859-1"); toHex(iso8859); byte[] gb2312=name.getBytes("GB2312"); toHex(gb2312); byte[] gbk=name.getBytes("GBK"); toHex(gbk); }
String str="小米"; byte[] b=str.getBytes("UTF-8");
public byte[] getBytes(String charsetName) throws UnsupportedEncodingException { if (charsetName == null) throw new NullPointerException(); return StringCoding.encode(charsetName, value, 0, value.length); }
static byte[] encode(String charsetName, char[] ca, int off, int len) throws UnsupportedEncodingException { StringEncoder se = deref(encoder); String csn = (charsetName == null) ? "ISO-8859-1" : charsetName; if ((se == null) || !(csn.equals(se.requestedCharsetName()) || csn.equals(se.charsetName()))) { se = null; try { Charset cs = lookupCharset(csn); //生成字符集實例 if (cs != null) se = new StringEncoder(cs, csn); } catch (IllegalCharsetNameException x) {} if (se == null) throw new UnsupportedEncodingException (csn); set(encoder, se); } return se.encode(ca, off, len); }
private static Charset lookupCharset(String csn) { if (Charset.isSupported(csn)) { try { return Charset.forName(csn); } catch (UnsupportedCharsetException x) { throw new Error(x); } } return null; }
private StringEncoder(Charset cs, String rcn) { this.requestedCharsetName = rcn; this.cs = cs; this.ce = cs.newEncoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE); this.isTrusted = (cs.getClass().getClassLoader0() == null); }
原創:https://blog.csdn.net/u010627840/article/details/50407575