中翻日許多人用 Java 處置到中文資料時,常會呈現亂碼翻譯關於 Java 和中文兼容性的問題,其實讓很多法式員為此傷透腦子,相幹的問題每隔幾天就會出現在網絡上。為了舒緩您緊蹙的眉頭,鉦昱翻譯公司出格寫了這系列文章,說明註解 Java 牽扯到文字時的內部處置懲罰體例,供讀者參考翻譯讀完本系列文章之後,生吞活剝者可以治標,充裕理解者可以治本翻譯本文貴在原理講解,別光是囫圇吞棗翻譯
快速解決之道
如果
1. 搜檢操作系統設定:先查抄你的操作系統,確定國籍說話資料是「Traditional Chinese(Taiwan)」翻譯國籍說話資料的設定會影響 Java 編譯器與JRE的判斷。我之前就是因為國籍資料設定不准確,出了一堆 Java 和中文不兼容的怪事。
2. 更新 Java 情況版本:改用最新版的 JDK,新版本的 JDK 說不定已解決
假如仍是沒法解決,請具體閱讀下面各小節的內容,細心推敲
Unicode、UTF-16、UTF-8
Java 內部處置懲罰字符利用的字序方式是 Unicode,這是一種通行全球的編碼體例翻譯Unicode 因為必需將中、韓、日、英、法、阿拉伯……等許多國度所使用的文字都納入,目前已經包含了六萬多個字符,所以 Unicode 利用了 16 個位來為字符編碼翻譯因為 Unicode 利用了 16 位編碼,所以每一個字符都用 16 位來貯存或傳輸是很天然的事,這種儲存或傳輸的格局稱為 UTF-16(是否是很像戰役機的名字)翻譯假如
關於 Unicode 的編碼,請查閱「The Unicode Standard翻譯社 Version 3.0」一書(Addison-Wesley 出版);關於 UTF-8 編碼,請查閱「Java I/O」一書的 399 頁(O'Reilly 出書)。關於 Java Class File 的花樣與 Constant Pool,請查閱「Java Virtual Machine」一書(O'Reilly出書)翻譯
Unicode 與繁體中文編碼的互轉
固然 Java 內部完全地使用 Unicode,可是你所利用的操作系統可不見得翻譯以繁體中文版的 Windows 98 來講,預設的編碼方式是 MS950,這是一種兼容於 Big 5的編碼體例。字符串數據從 Windows 一送進 JRE,JRE 的轉碼系統立地先把字符串編碼由 MS950 轉成 Unicode,才能進行處置。字符串資料由 JRE 一送出給 Windows,JRE 的轉碼系統頓時先將其由 Unicode 轉成 MS950,操作系統才能處置懲罰。
想知道你的 JDK 或 JRE 會用什麼樣的編碼方式來和操作系統溝通,請履行下面的 Java 程序:
public class ShowNativeEncoding {
public static void main(String[] args) {
String enc = System.getProperty("file.encoding");
System.out.println(enc);
}
}
如果履行後果不是下面的字符串之一,那麼你的操作系統國籍說話設定可能就有問題了:
· Big5:這是繁體中文 de facto 標準翻譯
· CNS11643:台灣的官方標準繁體中文編碼。
· Cp937:繁體中文加上 6204 個使用者自定的字符
· Cp948:繁體中文版 IBM OS/2 用的編碼體例。
· Cp964:繁體中文版 IBM AIX 用的編碼體式格局。
· EUC_TW:台灣的加強版 Unicode。
· ISO2022CN:編碼中文的一套標準。
· ISO2022CN_CNS:編碼中文的一套標準,繁體版,襲自 CNS11643翻譯
· MS950 或 Cp950:ASCII + Big5,用於台灣和香港的繁體中文 MS Windows操作系統。
· Unicode:有順序記號的 Unicode。次序記號佔用兩個 byte,如果其值是0xFEFF,透露表現使用 big-endian(由大到小)的順序為 Unicode 編碼;假如其值是 0xFFFF,默示利用 little-endian(由小到大)的順序為 Unicode 編碼。
· UnicodeBig:使用 big-endian(由大到小)的次序為 Unicode 編碼。
· UnicodeLittle:利用 little-endian(由小到大)的順序為 Unicode 編碼。
· UTF8:利用 UTF-8 為 Unicode 編碼。
關於 Big 5 編碼,請查閱「CJKV Information Processing」一書的附錄 H(O'Reilly出書)翻譯
編譯時的注意事項
編譯的時辰,如果你不申明原始文件編碼體式格局的話, javac 編譯器在讀進此原始程序文件,起頭編譯之前,會先去詢問操作系統檔案預設的編碼方式為何。以繁體中文 Windows 98 來講,javac 會先詢問 Windows 98,得知檔案是用 MS950 的體例編碼。然後就能夠將檔案由 MS950 轉成 Unicode 編碼體例,開始進行編譯翻譯
凡是在編譯階段,會釀成的錯誤有以下幾種可能:
1. 假如操作系統的國籍資料設定毛病,會造成 javac 編譯器獲得的編碼信息是錯的。
2. 較低劣的編譯器可能沒有主動扣問操作系統的編碼體式格局,而是採用編譯器預設的編碼體式格局翻譯
3. 如果原始法式不是用編譯其時操作系統預設的編碼體例存盤的,也會造成毛病。譬喻說,原始程序文件是台灣程序員寫的,在繁體中文版的 Windows上以 MS950 編碼存盤,再經過網絡傳送到泰國,在泰文版的 Windows 上編譯(泰文版 Windows 預設的檔案編碼方式是 MS874)。
這類因為原始法式文件編碼體例和編譯器無法匹配所釀成的問題,輕則編譯成功但履行時文字出現亂碼或呈現 Error/Exception,重則無法成功編譯。這時候,你需要自動透過「-encoding」選項來指定原始程序的編碼體例,編譯器會以
javac –encoding MS950 TaiwanClass.java
假如你手上只有某 class 文件,沒有原始法式文件,而且你確定其 constant pool 的UTF-8 字段編碼毛病,你有兩種體式格局可以用來批改編碼:
1. 先反編譯,獲得原始法式,再修改,編譯翻譯
2. 或直接行使 bytecode 編輯軟件,直接點竄 class 文件。
I/O 轉碼
Java 現行的 IO 一律使用 Stream 的體式格局,相關的種別都放在 java.io 中。輸出 binary 的資料利用 OutputStream 的子種別,輸入 binary 的資料利用 InputStream 的子種別,輸出文字的資料使用 Writer 的子種別,輸入文字的資料使用 Reader 的子種別。
你可能會感覺很新鮮:「有必要用分歧的體式格局來處置懲罰文字和 binary 嗎?文字資料不也是 binary 的一種?」沒錯,其實他們非常近似,最大的差別在於,InputStream/OutputStream 會原封不動地傳送資料,可是 Reader/Writer 會將資料看成文字看待,所以 Reader/Writer 在「必要時」會把(文字)資料轉碼。什麼時候才是所謂的「需要時」呢?
Java 的 Stream(包括 Reader 和 Writer)是可以互相串接的。當 Reader 的資料來曆是另外一個 Reader 時,不轉碼,當 Reader 的資料濫觞是一個 InputStream 時,就會轉碼。當 Writer 的資料去處是另外一個 Writer 時,不轉碼,當 Writer 的資料行止是一個 OutputStream 時,就會轉碼翻譯
由什麼碼轉成什麼碼?這是可以指定的。因為轉碼只發生在 Reader/InputStream 的交壤處與 Writer/OutputStream 的交界處,所以正是由 InputStreamReader 和 OutputStreamWriter 此二種別負責,下面兩個 constructor 的第二個參數,正是用來指定轉碼的體例。
public InputStreamReader(InputStream in, String enc)
throws UnsupportedEncodingException;
public OutputStreamWriter(OutputStream out, String enc)
throws UnsupportedEncodingException;
InputStreamReader 負責將 enc 的編碼體式格局轉成 Unicode(因為資料是從「外部」送過來給「內部」的),OutputStreamWriter 負責將 Unicode 的編碼體例轉成 enc(因為資料要從「內部」送給「外部」)。JRE 內部固然都必然是用 Unicode 編碼,而外部的編碼就不一定,要看當時的情況為何。你可以透過 getEncoding() 的 method,來得知 InputStreamReader 與 OutputStreamWriter 的編碼體式格局。
請注意:即便
如果你清晰地知道
檔案 I/O 轉碼
假如你是在泰文版的 Windows 上,想讀取用 MS950 編碼的繁體中文文字文件,
FileInputStream fis = new FileInputStream(fileName);
InputStreamReader reader = new InputStreamReader(fis, "MS950");
然後,透過 Reader 讀出來的就會是正確的中文。
收集 I/O 轉碼
若是你的收集法式採用 TCP,那麼你可以透過 Socket 種別所提供的 getInputStream() 和 getOutputStream() 來獲得 InputStream 和 OutputStream 對象。如果
InputStream is = mySocket.getInputStream();
InputStreamReader reader = new InputStreamReader(is, "MS950");
若是
如果你的網絡法式採用 RMI,那你完全不用為這部份的轉碼操心,字符串直接用 Unicode 在收集上傳遞給另外一個 JRE,不需要轉碼翻譯
連結刑案現場
若是你不知道你的 I/O 資料起原或行止是用何種編碼方式,那麼
字符串和 byte 數組的轉碼
java.lang.String 類別是 Java 字符串對象的種別,Java 字符串對像既然是活在 JRE 內部,當然就必然是用 Unicode 編碼。假如你需要將 String 對像和 byte 數組互轉,
String(byte[] bytes, int offset翻譯社 int length翻譯社 String enc);
或
String(byte[] bytes, String enc);
來將用 enc 編碼的 byte 數組,轉成 Unicode 的 String 對象。你也可以利用 String 對像所供給的:
byte[] getBytes(String enc)
來將 String 對像轉成 byte 數組。
別的,你也能夠透過 ByteArrayInputStream 或 ByteArrayOutputStream 串接到 InputStreamReader 或 OutputStreamWriter,來到達轉碼的目的。
文章出自: https://blog.xuite.net/evan_0412/wretch/169912286-JAVA%E4%BA%82%E7%A2%BC%E5%95%8F%E9%A1%8C%EF%BC%88%有關各國語文翻譯公證的問題歡迎諮詢鉦昱翻譯公司02-23690937
- Oct 25 Thu 2018 07:08
JAVA亂碼問題(轉載自網路) @ Java A+
close
文章標籤
全站熱搜
留言列表