編碼決定「字元 → 位元組序列」的映射規則;字型決定「字元 → 字形」的繪製規則。亂碼 99% 是編碼不匹配,非字型缺失。
| 編碼 | 類型 | 中文支援 | Java 名稱別名 | 備註 |
|---|---|---|---|---|
| ASCII / ISO-8859-1 | 單位元組 | ❌ | ISO8859_1, 8859_1 | 預設編碼,中文全變 ? |
| GB2312 / GBK / GB18030 | 雙位元組 (DBCS) | ✅ 簡體 | GB2312, GBK, GB18030, cp936 | 國標,GBK/18030 為超集 |
| Big5 / Big5-HKSCS | 雙位元組 | ✅ 繁體 | Big5, Big5-HKSCS, cp950 | 繁體中文主流 |
| UTF-8 | 可變長 (1~3 bytes) | ✅ 全 Unicode | UTF-8, UTF8, utf8 | 網路傳輸、JAD、XML 標準 |
| UTF-16 (UCS-2) | 固定 2 bytes | ✅ BMP 字元 | UTF-16, UCS-2, UnicodeBigUnmarked | Nokia 常用 "ucs-2" |
// 解碼:byte[] → String
String s = new String(byteArr, "GB2312");
// 編碼:String → byte[]
byte[] b = s.getBytes("UTF-8");
// 異常:UnsupportedEncodingException → 裝置不支援該編碼
// 偵測裝置支援度
boolean supported(String enc) {
try { "測試".getBytes(enc); return true; }
catch (UnsupportedEncodingException e) { return false; }
}
// DataInput/OutputStream 的 UTF-8 變體 (長度前綴 2 bytes)
DataOutputStream dos = new DataOutputStream(out);
dos.writeUTF(str); // 寫入長度 + UTF-8 bytes
DataInputStream dis = new DataInputStream(in);
String s2 = dis.readUTF();
// 方案 A:UTF-8 (通用、無需偵測)
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeUTF("中文內容");
rs.addRecord(bos.toByteArray(), 0, bos.size());
// 讀回
byte[] data = rs.getRecord(id);
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data));
String s = dis.readUTF();
// 方案 B:GB2312 (省空間,需先確認支援)
byte[] b = "中文".getBytes("GB2312");
rs.addRecord(b, 0, b.length);
// 讀回
String s = new String(rs.getRecord(id), "GB2312");
getResourceAsStream) 讀取中文| 檔案編碼 | 讀取代碼 | 關鍵點 |
|---|---|---|
| UTF-8 | new String(bytes, "UTF-8") | 最通用 |
| UTF-16LE (低位在前) | new String(bytes, "UTF-16LE") 或手動解碼 + BOM FF FE | Nokia 稱 "ucs-2" 實為 LE |
| UTF-16BE (高位在前) | new String(bytes, "UTF-16BE") 或 "ucs-2" (視裝置) | 需確認 BOM FE FF |
| GB2312/Big5 | new String(bytes, "GB2312") | 需裝置支援 |
實戰技巧:文字編輯器 (Notepad++/UltraEdit) 另存新檔時選編碼;打包進 JAR 前用 hexdump 確認 BOM 與位元組序。
Content-Type: text/plain; charset=UTF-8,客戶端讀標頭決定解碼。parser.setInput(is, "UTF-8");若 null 則自動偵測 XML 宣告 。Content-Type: text/vnd.sun.j2me.app-descriptor; charset=UTF-8,否則 Nokia S40 等裝置安裝後顯示亂碼。// 任意支援編碼間互轉:以 UTF-8 為中介
String unicode = new String(gbBytes, "GB2312"); // 解碼
byte[] utf8Bytes = unicode.getBytes("UTF-8"); // 編碼
// 直接轉換 (不建議,易出錯)
// byte[] big5 = new String(gbBytes, "GB2312").getBytes("Big5");
原則:解碼用來源編碼,編碼用目標編碼,中介用 String (內部 UTF-16)。
Hashtable 存預編碼結果,佔 ~幾 KB。| 現象 | 可能原因 | 驗證方法 |
|---|---|---|
| 全問號 ???? | 編碼不支援 / 解碼錯誤 | 印出 byte[] 十六進位,對照編碼表 |
| 半亂碼 (部分正常) | 資料截斷 / 奇數位元組截斷 (DBCS) | 檢查長度是否為偶數 |
| 方塊 □ / 缺字 | 字型無對應字形 | 換支援 Unicode 字型或用位圖字體 |
| JAD 安裝後亂碼 | 伺服器未送 charset=UTF-8 | 抓包檢查 Content-Type 標頭 |
J2ME 中文亂碼本質是「編碼協議不一致」。建立「來源編碼 → 統一內部 Unicode (String) → 目標編碼」的標準化流程,配合 UnsupportedEncodingException 自動偵測裝置能力,即可覆蓋 99% 實戰場景。記住:UTF-8 是通用橋樑,JAD/HTTP/XML 強制 UTF-8,本地儲存視空間選 GB2312/Big5。