JAVA encoding

現代計算機採用的都是馮.諾依曼體系結構,因此都具有相同的結構特徵,擁有五大組成部分:輸入數據和程序的輸入設備,記憶程序和數據的存儲器,完成數據加工處理的運算器,控制程序執行的控制器,輸出處理結果的輸出設備。JVM是一臺虛擬的計算機,也有類似的特徵。本系列文章研究的是java中文問題,跟輸入輸出有着密切的聯繫,爲了突出重點,我們暫且將JVM的其它細節放下,只需瞭解JVM內部的數據是用Unicode表示的,使用的編碼方式是UTF-16(至於是UTF-16LE還是UTF-16BE就要看具體的虛擬機實現了,intel x86 -windows 下是UTF-16LE,這可以使用 System.getProperty("sun.io.unicode.encoding") 取得)。 
      現在我們具體來看運行一個控制檯程序所經歷的步驟以及這個過程中涉及到輸入和輸出。一個程序從源代碼到運行大概會經歷這麼一個過程:
      1、使用一個文本編輯器編寫java源代碼,完畢後保存到一個.java文件中。如果指定文件的保存格式(GBK,UTF-8 ect.),則用指定的格式保存,否則使用默認編碼方式保存(記事本,Editplus,eclipse等都是使用系統默認的編碼方式GBK)。
      2、使用javac命令編譯.java源文件,產生.class文件,以UTF-8格式保存。注意,.class文件的格式必須是UTF-8,不需要指定,也不管系統默認的編碼方式是什麼。
      3、使用java程序,運行jvm,載入編譯好的.class文件,程序開始運行。
      4、運行過程中,程序從輸入(標準輸入,文件,網絡)中取得數據,進行相應的編碼轉換後放進JVM,以供運算使用。運算完畢後,將產生的數據進行編碼轉換後輸出到指定位置(標準輸出,文件,網絡)
      這樣,程序就一直運行下去,直到結束。這期間,哪些地方有可能出現中文問題呢?下面一一道來:
      1、使用javac進行編譯時。如果我們.java源文件保存的編碼方式跟javac指定的讀入編碼方式不一致,則會出現中文問題。譬如,我們在中文windows環境下用eclipse編寫好源文件,然後到一個英文linux環境下進行編譯,如果javac時沒有指定編碼方式爲GBK,那麼javac就會按照當前系統的默認編碼方式(ISO-8859-1)進行解析,雖然裏面的英文字符是不會出錯的,但是中文就全部變成亂碼了,也就是說,javac產生的.class文件中存儲的中文字符是錯誤的。這樣,運行的時候肯定也就出問題了。
      建議 1 :保存.java源文件時使用UTF-8進行保存,在使用javac編譯的時候通過參數 -encoding UTF-8指定編碼方式。這樣,可以保證源程序在任何支持UTF-8的平臺上都能通過編譯。PS:通過記事本的另存爲將一個源文件保存成UTF-8時,會在文件頭部加上一個BOM(ef bb bf),javac會報錯。但是用Editplus,eclipse卻不會出現這種問題。


     2、控制檯跟操作系統密切相關,標準輸入輸出的編碼都是固定的,也就是系統的默認編碼,這是不能動態改變的。如果你程序裏有中文編碼,在中文環境下調用System.out.println("漢"); jvm會自動將輸出流轉換爲GBK字節串交給控制檯,控制檯使用默認編碼就正確輸出了。但是該語句在英文環境下運行的話,那裏的默認編碼是ISO-8859-1,jvm就將“漢”轉換成相應編碼交給控制檯,也就是兩個“?”了。
      建議 2:如果程序要跨平臺的話,程序裏用到控制檯輸出的代碼最好不用中文字符。

     3、如果數據來自網絡或者文件的話,數據源的編碼方式可以多種多樣。因此,我們在讀入的時候一定要清楚數據源的編碼方式,通知jvm進行正確的處理,否則也會出現中文問題。下面以文件讀寫爲例。
      java 中處理字符的讀寫一般使用FileReader和FileWriter。但是這兩個類都是使用系統默認的字符編碼進行文件的讀寫,而且不能更改處理時的編碼方式。也就是說,在GBK平臺只能處理GBK的文件,在ISO-8859-1的平臺只能處理ISO-8859-1的文件,這當然是不能接受的。因此,使用InputStreamReader 和 OutputStreamWriter吧。只要你能保證數據源的編碼方式,然後讀寫時配置好相應的讀寫器的編碼方式,就不會出現中文問題了。
     建議 3 :使用文件進行數據交換時,最好統一文件的編碼方式,如UTF-8。雖然對於中文來說,體積會增大50%,但是換來的是很好的跨平臺特性。xml就是一個很好的例子。

     如果能很好地做到上面幾條,那麼對於一個控制檯應用程序來說應該是可以避免中文問題了。

PS:爲了更好理解,轉自他處的資料:
 
編碼方式的簡介:

String序列化成byte數組或反序列化時需要選擇正確的編碼方式。如果編碼方式不正確,就會得到一些0x3F的值。常用的字符編碼方式有ISO8859_1、GB2312、GBK、UTF-8/UTF-16/UTF-32。
ISO8859_1用來編碼拉丁文,它由單字節(0-255)組成。
GB2312、GBK用來編碼簡體中文,它有單字節和雙字節混合組成。最高位爲1的字節和下一個字節構成一個漢字,最高位爲0的字節是ASCII碼。
UTF-8/UTF-16/UTF-32是國際標準UNICODE的編碼方式。 用得最多的是UTF-8,主要是因爲它在對拉丁文編碼時節約空間。
UNICODE值 UTF-8編碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章