Java 內部字符串為 UTF-16 (char 2 字節)。J2ME 環境下,為了節省頻寬、存儲空間並兼容中英文混排,**所有外部交互 (網絡、文件、RMS) 均採用 UTF-8 編碼** 是行業標準做法。
錯誤做法:直接用 OutputStream.write(bytes[]) / InputStream.read(bytes[]) 按字節傳輸,編碼不一致導致亂碼。
正確做法:封裝為 DataOutputStream / DataInputStream,使用 writeUTF(String) / readUTF()。
SocketConnection conn = (SocketConnection) Connector.open("socket://server:port");
DataOutputStream dos = conn.openDataOutputStream();
dos.writeInt(msgType); // 先寫 int
dos.writeByte(subType); // 再寫 byte
dos.writeUTF(chineseText); // 最後寫 UTF-8 字符串 (含長度前綴)
dos.flush();
DataInputStream dis = conn.openDataInputStream();
int type = dis.readInt();
byte sub = dis.readByte();
String text = dis.readUTF(); // 自動解碼 UTF-8
HttpConnection conn = (HttpConnection) Connector.open(url);
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
OutputStream os = conn.openOutputStream();
// 手動構造 application/x-www-form-urlencoded 體,值需 URLEncoder.encode(str, "UTF-8")
String body = "param=" + URLEncoder.encode(chineseText, "UTF-8");
os.write(body.getBytes("UTF-8")); // MIDP 可能無 getBytes(encoding),需手動轉碼或用 DataOutputStream
os.flush();
注意:MIDP 無 java.net.URLEncoder,需自行實現或使用第三方輕量庫。
RMS 只接受 byte[]。流程:String → UTF-8 byte[] → 存入 RecordStore → 讀出 byte[] → UTF-8 String。
RecordStore rs = RecordStore.openRecordStore("MyData", true);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeUTF(chineseString); // 關鍵:writeUTF 自動處理 UTF-8 編碼 + 長度前綴
byte[] data = baos.toByteArray();
rs.addRecord(data, 0, data.length);
dos.close();
baos.close();
byte[] data = rs.getRecord(recordId);
ByteArrayInputStream bais = new ByteArrayInputStream(data);
DataInputStream dis = new DataInputStream(bais);
String restored = dis.readUTF(); // 自動解碼
dis.close();
bais.close();
步驟:
res/ 目錄,打包進 JAR
public String readResourceAsUTF8(String resourcePath) {
InputStream is = getClass().getResourceAsStream(resourcePath);
if (is == null) return null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
byte[] data = baos.toByteArray();
// 關鍵:指定 UTF-8 解碼 (MIDP 支持 String(byte[], String encoding))
return new String(data, "UTF-8");
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
try { is.close(); } catch (Exception ignored) {}
}
}
// 讀取 res/config.txt (UTF-8 編碼)
String config = readResourceAsUTF8("/config.txt");
// 讀取 res/messages_zh.properties
String msg = readResourceAsUTF8("/messages_zh.properties");
| 場景 | 錯誤現象 | 根因 | 修正 |
|---|---|---|---|
| 網絡傳輸 | 中文亂碼/截斷 | 直接 write(bytes) 無編碼協議 | DataOutputStream.writeUTF / readUTF |
| HTTP 參數 | 服務端收到亂碼 | 未 URLEncode 或編碼不一致 | 手動 UTF-8 URLEncode + Content-Type charset=UTF-8 |
| RMS 存儲 | 讀出亂碼 | String.getBytes() 使用平台默認編碼 | DataOutputStream.writeUTF / DataInputStream.readUTF |
| 資源文件 | 讀出亂碼 | 文件非 UTF-8 / 讀取未指定編碼 | 文件存 UTF-8 無 BOM + new String(bytes, "UTF-8") |
| 跨平台 | 模擬器正常、實機亂碼 | 實機默認編碼非 UTF-8 (如 GBK) | 所有外部交互強制指定 UTF-8 |
極少數精簡設備可能缺失 DataOutputStream,可自行實現:
// 簡易 UTF-8 編碼 (僅供參考,生產建議用標準庫)
public static byte[] encodeUTF8(String s) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c <= 0x7F) {
baos.write(c);
} else if (c <= 0x7FF) {
baos.write(0xC0 | (c >> 6));
baos.write(0x80 | (c & 0x3F));
} else {
baos.write(0xE0 | (c >> 12));
baos.write(0x80 | ((c >> 6) & 0x3F));
baos.write(0x80 | (c & 0x3F));
}
}
return baos.toByteArray();
}
J2ME 中文處理鐵律:**內部 Unicode (char/String) → 外部統一 UTF-8**。三大場景通用模板:DataOutputStream.writeUTF / DataInputStream.readUTF (網絡/RMS) + new String(bytes, "UTF-8") (資源文件)。文件源碼編輯器務必設置為 UTF-8 無 BOM,徹底杜絕亂碼。