需將 數字ID + 中文名 + 圖片二進制 序列化為單一 byte[] 存入 RMS (RecordStore)。模擬器 (Windows, Cp1252/GBK) 正常,真機 (預設 ISO-8859-1) 讀出亂碼。
| 環境 | 預設字符集 | Java 內部 char |
|---|---|---|
| Windows 中文版 | Cp936 (GBK) | UTF-16LE |
| Linux/Unix | UTF-8 | UTF-16LE |
| J2ME 真機 (CLDC/MIDP) | ISO-8859-1 (Latin-1) | UTF-16LE |
核心矛盾:String.getBytes() 無參數時使用平台預設編碼,真機上為 ISO-8859-1,**無法表示漢字** → 丟失信息。
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeUTF(str); // 修改 UTF-8 變長編碼,前兩字節寫長度
byte[] data = baos.toByteArray();
失敗原因:writeUTF 采用 **Modified UTF-8**,長度字段為 **unsigned short (2 字節)**,最大 65535 字節。圖片數據動輒數十 KB,加上字串極易超限 → UTFDataFormatException。
// 1. 字串部分顯式 UTF-8 編碼
String meta = strID + strName; // 純文本元數據
byte[] metaBytes = meta.getBytes("UTF-8"); // 關鍵:強制 UTF-8
// 2. 圖片二進制已為 byte[],無需編碼
byte[] picBytes = ...; // Image → PNG/JPG 字節數組
// 3. 手動拼裝:長度前綴 + 元數據 + 圖片數據
// 協議:[metaLen:2 bytes big-endian][metaBytes][picBytes]
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(bos);
out.writeShort(metaBytes.length); // 2 字節長度,支援 64KB 元數據
out.write(metaBytes);
out.write(picBytes);
byte[] record = bos.toByteArray();
recordStore.addRecord(record, 0, record.length);
byte[] record = recordStore.getRecord(recordId);
DataInputStream in = new DataInputStream(new ByteArrayInputStream(record));
int metaLen = in.readUnsignedShort(); // 0~65535
byte[] metaBytes = new byte[metaLen];
in.readFully(metaBytes);
String meta = new String(metaBytes, "UTF-8"); // 關鍵:對應寫入編碼
// 解析 meta → strID, strName (自定分隔符或定長)
byte[] picBytes = new byte[record.length - 2 - metaLen];
in.readFully(picBytes);
// picBytes 即為原始圖片數據,可直接 Image.createImage(picBytes, 0, picBytes.length)
getBytes("UTF-8")、new String(bytes, "UTF-8"),杜絕無參重載。-Dfile.encoding=UTF-8,盡早暴露問題。// 讀取時嘗試雙重解碼
String tryUtf8 = new String(metaBytes, "UTF-8");
if (looksLikeGarbage(tryUtf8)) { // 簡單啟發式:含大量 或控制字符
return new String(metaBytes, "ISO-8859-1"); // 兼容舊數據
}
return tryUtf8;