java 中文亂碼以及轉碼

查看此文章須要對字符集編碼有必定的認識:任意門:字符集編碼基礎

1、字符串的內部表示?

重點:字符串在java(指在JVM中、在內存中)中統一用unicode表示( 即utf-16 LE) , 下面解釋:html

對於 String s = "你好哦!";java

若是源碼文件(java文件)是GBK編碼, 操做系統(windows)默認的環境編碼爲GBK,那麼編譯時,  JVM將 按照GBK編碼將字節數組解析成字符(系統文件本質就是二進制流),而後將字符轉換爲unicode格式的字節數組,做爲內部存儲。windows

當打印這個字符串時,JVM 根據操做系統本地的語言環境,將unicode轉換爲GBK,而後操做系統將GBK格式的內容顯示出來。數組

 

當源碼文件是UTF-8, 咱們須要通知編譯器源碼的格式,javac -encoding utf-8 ... , 編譯時,JVM按照utf-8 解析成字符,而後轉換爲unicode格式的字節數組, 因此不論源碼文件是什麼格式,一樣的字符串,最後獲得的unicode字節數組是徹底一致的,顯示的時候,也是轉成GBK來顯示(跟OS環境有關:OS表示操做系統)tomcat

 

2、亂碼如何產生? 本質上都是因爲 字符串本來的編碼格式 與 讀取時解析用的編碼格式不一致致使的。

例如:this

String s = "你好哦!";編碼

System.out.println( new String(s.getBytes(),"UTF-8")); //錯誤,由於getBytes()默認使用GBK編碼, 而解析時使用UTF-8編碼,確定出錯。spa

其中 getBytes() 是將unicode 轉換爲操做系統默認的格式的字節數組,即"你好哦"的 GBK格式,操作系統

new String (bytes, Charset) 中的charset 是指定讀取 bytes 的方式,這裏指定爲UTF-8,即把bytes的內容當作UTF-8 格式對待。code

以下兩種方式都會有正確的結果,由於他們的源內容編碼和解析用的編碼是一致的。

System.out.println( new String(s.getBytes(),"GBK"));

System.out.println( new String(s.getBytes("UTF-8"),"UTF-8"));

 

3、如何利用getBytes 和 new String() 來進行編碼轉換呢?

 網上流傳着一種錯誤的方法:

GBK--> UTF-8:    new String( s.getBytes("GBK") , "UTF-8);   ,這種方式是徹底錯誤的,由於getBytes 的編碼與  UTF-8 不一致,確定是亂碼。

可是爲何在tomcat 下,使用 new String(s.getBytes("iso-8859-1") ,"GBK") 卻能夠用呢? 答案是:

tomcat 默認使用iso-8859-1編碼, 也就是說,若是本來字符串是GBK的,tomcat傳輸過程當中,將GBK轉成iso-8859-1了,

默認狀況下,使用iso-8859-1讀取中文確定是有問題的,那麼咱們須要將iso-8859-1 再轉成GBK, 而iso-8859-1 是單字節編碼的,

即他認爲一個字節是一個字符, 那麼這種轉換不會對原來的字節數組作任何改變,由於字節數組原本就是由單個字節組成的,

若是以前用GBK編碼,那麼轉成iso-8859-1後編碼內容徹底沒變, 則 s.getBytes("iso-8859-1")  實際上仍是原來GBK的編碼內容

則 new String(s.getBytes("iso-8859-1") ,"GBK")  就能夠正確解碼了。 因此說這是一種巧合。

 

4、如何正確的將GBK轉UTF-8 ? (其實是unicode轉UTF-8)

String gbkStr = "你好哦!"; //源碼文件是GBK格式,或者這個字符串是從GBK文件中讀取出來的, JVM會把字符轉化成unicode格式

//利用getBytes將unicode字符串轉成UTF-8格式的字節數組

byte[] utf8Bytes = gbkStr.getBytes("UTF-8"); 

//而後用utf-8 對這個字節數組解碼成新的字符串

String utf8Str = new String(utf8Bytes, "UTF-8");

簡化後就是:

unicodeToUtf8 (String s) {

return new String( s.getBytes("utf-8") , "utf-8");

}

UTF-8 轉GBK原理也是同樣

return new String( s.getBytes("GBK") , "GBK");

 

 其實核心工做都由  getBytes(charset) 作了。

getBytes 的JDK 描述:Encodes this String into a sequence of bytes using the named charset, storing the result into a new byte array.

 

另外對於讀寫文件,

OutputStreamWriter w1 = new OutputStreamWriter(new FileOutputStream("D:\\file1.txt"),"UTF-8");

InputStreamReader( stream, charset)

能夠幫助咱們輕鬆的按照指定編碼讀寫文件。

相關文章
相關標籤/搜索