翻譯公司很多人用 Java 處置到中文資料時,常會泛起亂碼翻譯關於 Java 和中文兼容性的問題,實在讓很多法式員為此傷透腦筋,相幹的問題每隔幾天就會呈現在收集上。為了舒緩您緊蹙的眉頭,華頓翻譯公司特別寫了這系列文章,解說 Java 牽涉到文字時的內部處置懲罰體例,供讀者參考翻譯讀完本系列文章以後,囫囵吞棗者可以治標,充裕理解者可以治本。本文貴在原理說明註解,別光是囫圇吞棗翻譯

快速解決之道

若是翻譯公司今朝正遭受到 Java 和中文不兼容的問題,請翻譯公司注意下面這幾點,說不定問題能立地迎刃而解:

1.          檢查操作系統設定:先檢查你的操作系統,肯定國籍說話資料是「Traditional Chinese(Taiwan)」翻譯國籍說話資料的設定會影響 Java 編譯器與JRE的判斷翻譯我之前就是因為國籍資料設定不正確,出了一堆 Java 和中文不兼容的怪事翻譯

2.          更新 Java 情況版本:改用最新版的 JDK,新版本的 JDK 說不定已經解決你原本的問題翻譯請注意:某些 Java IDE 所用的編譯器和 JRE 是不兼容於中文的(我遇過如許的景遇),你最好能把 Java IDE 的 JDK 指到新版的 JDK翻譯另外,如果數據庫取回的資料是亂碼,換別套或更新 JDBC 驅動法式碰運氣。

若是照樣無法解決,請詳細閱讀下面各末節的內容,細心斟酌你的錯誤地點翻譯

Unicode、UTF-16、UTF-8

Java 內部處理字符使用的字序體例是 Unicode,這是一種通行全球的編碼體例。Unicode 因為必需將中、韓、日、英、法、阿拉伯……等許多國家所利用的文字都納入,今朝已包括了六萬多個字符,所以 Unicode 利用了 16 個位來為字符編碼。因為 Unicode 使用了 16 位編碼,所以每一個字符都用 16 位來貯存或傳輸是很自然的事,這類貯存或傳輸的格局稱為 UTF-16(是不是很像戰鬥機的名字)。如果翻譯公司利用到的字符都是西方字符,那麼你必然不會想用 UTF-16 的格局,因為體積比 8 位的 Latin-1(一種擴充 ASCII 的編碼)多了一倍。所以 Unicode 尚有一種貯存或傳輸的花式,叫做 UTF-8。UTF-8 的格式在編碼英文時,只需要 8 位,可是中文則是 24 位,所以中文字泛起比例高的處所還是利用 UTF-16 對照節流空間。Java 的 Class File(也就是 bytecode)中有一字段叫做常數區(Constant Pool),一概使用 UTF-8 為字符編碼。

關於 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」選項來指定原始法式的編碼方式,編譯器會以你指定的編碼為主,不會再去扣問操作系統。下面的例子,我們告知編譯器「TaiwanClass.java」是以繁體中文版 Windows 的「MS950」編碼的:

       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 的編碼體例。

請注意:即便翻譯公司沒用到 InputStreamReader 與 OutputStreamWriter,只有效到其它的 Reader 和 Writer,但是這些 Reader 和 Writer 內部也很有可能(但非絕對)是直接或間接通到 InputStreamReader 與 OutputStreamWriter。譬喻說:FileReader 內部實際上是透過一個 InputStreamReader 的中介來將資料從 FileInputStream 取過來的,此時 InputStreamReader 的轉碼體例是採用 OS 的文字編碼(以繁體中文的 Windows 為例,就是「MS950」)轉成 Unicode翻譯

假如你清楚地知道翻譯公司要讀寫的檔案(或資料濫觞 / 行止)是採用某種編碼體例,翻譯公司也可以自動指定編碼體式格局。可是,請記得抓取可能致使的 UnsupportedEncodingException,並務必處理之,不行對此例外充耳不聞,因為該 JRE 有可能沒有附上此種編碼表(也有可能你的編碼名稱給錯)。

檔案 I/O 轉碼
如果你是在泰文版的 Windows 上,想讀取用 MS950 編碼的繁體中文文字文件,你就必需自動指定編碼,不行以直接用 FileReader,不然無法成功讀取。方式以下:

FileInputStream fis = new FileInputStream(fileName);
InputStreamReader reader = new InputStreamReader(fis, "MS950");

然後,透過 Reader 讀出來的就會是准確的中文。

網絡 I/O 轉碼
若是你的收集法式採用 TCP,那麼翻譯公司可以透過 Socket 種別所提供的 getInputStream() 和 getOutputStream() 來獲得 InputStream 和 OutputStream 對象。假如翻譯公司是在泰文版的 Windows 上,想讀取用 MS950 編碼的繁體中文文字 TCP 收集串流,你可以用類似上面的技能來轉碼。方法如下:

InputStream is = mySocket.getInputStream();
InputStreamReader reader = new InputStreamReader(is, "MS950");

若是你的收集法式採用 UDP,翻譯公司必需把中文字符串轉成(或轉自)byte 數組翻譯請看下一節「 字符串和 byte 數組的轉碼 」。

若是你的網絡法式採用 RMI,那你完全不消為這部分的轉碼費心,字符串直接用 Unicode 在收集上傳遞給另一個 JRE,不需要轉碼。

保持刑案現場
若是你不知道你的 I/O 資料來源或去處是用何種編碼體例,那麼你最好不要用 Reader 和 Writer,而應當直接用 InputStream 和 OutputStream,因為與其被 Reader 和 Writer 胡亂編碼以後造成信息遺失或錯亂,不如保持資料的完全不變,留待今後進一步解讀翻譯

字符串和 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-77260932

arrow
arrow
    文章標籤
    翻譯社
    全站熱搜
    創作者介紹
    創作者 johnnijmp3w 的頭像
    johnnijmp3w

    johnnijmp3w@outlook.com

    johnnijmp3w 發表在 痞客邦 留言(0) 人氣()