首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME RMS 讀寫實戰:中文存儲解決方案與最佳實踐模板

     編輯:J2ME

前言:RMS 不支持中文的根因與對策

RecordStore (RMS) 底層以字節數組存儲,RecordStore.addRecord(byte[]) 無字符集概念。直接存儲 String.getBytes() 會因平台默認編碼差異導致中文亂碼。標準解決方案:使用 DataOutputStream.writeUTF() / DataInputStream.readUTF(),採用 **Modified UTF-8** 格式,跨平台安全。

核心編解碼工具類


import java.io.*;

public class RmsCodec {
    /** 字符串 → 字節數組 (Modified UTF-8) */
    public static byte[] toBytes(String str) {
        if (str == null) return new byte[0];
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        try {
            dos.writeUTF(str);
            dos.flush();
            return baos.toByteArray();
        } catch (IOException e) {
            return new byte[0];
        } finally {
            try { dos.close(); } catch (IOException ignored) {}
            try { baos.close(); } catch (IOException ignored) {}
        }
    }

    /** 字節數組 → 字符串 (Modified UTF-8) */
    public static String toString(byte[] data) {
        if (data == null || data.length == 0) return "";
        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        DataInputStream dis = new DataInputStream(bais);
        try {
            return dis.readUTF();
        } catch (IOException e) {
            return "";
        } finally {
            try { dis.close(); } catch (IOException ignored) {}
            try { bais.close(); } catch (IOException ignored) {}
        }
    }
}

完整 RMS 封裝類:單記錄存儲模式


import javax.microedition.rms.*;

public class SimpleRmsStore {
    private static final String RECORD_STORE_NAME = "UserConfig";
    private RecordStore rms;

    /** 讀取記錄 (單記錄模式) */
    public String read() {
        try {
            rms = RecordStore.openRecordStore(RECORD_STORE_NAME, true,
                    RecordStore.AUTHMODE_ANY, true);
            int count = rms.getNumRecords();
            if (count == 0) return "";
            // 僅讀取第一條記錄 (ID=1)
            return RmsCodec.toString(rms.getRecord(1));
        } catch (Exception e) {
            return "";
        } finally {
            closeQuietly();
        }
    }

    /** 保存記錄 (覆蓋模式:無則創建,有則更新) */
    public String save(String data) {
        try {
            rms = RecordStore.openRecordStore(RECORD_STORE_NAME, true,
                    RecordStore.AUTHMODE_ANY, true);
            byte[] bytes = RmsCodec.toBytes(data);
            
            if (rms.getNumRecords() == 0) {
                rms.addRecord(bytes, 0, bytes.length); // 創建第一條
            } else {
                rms.setRecord(1, bytes, 0, bytes.length); // 更新第一條
            }
            return "保存成功";
        } catch (Exception e) {
            return "保存失敗: " + e.getMessage();
        } finally {
            closeQuietly();
        }
    }

    /** 刪除記錄存儲 (重置) */
    public void clear() {
        try {
            RecordStore.deleteRecordStore(RECORD_STORE_NAME);
        } catch (Exception ignored) {}
    }

    private void closeQuietly() {
        if (rms != null) {
            try { rms.closeRecordStore(); } catch (Exception ignored) {}
            rms = null;
        }
    }
}

進階模式:多記錄列表存儲


public class ListRmsStore {
    private static final String STORE_NAME = "GameScores";
    private RecordStore rms;

    /** 保存分數列表 (每條記錄一個分數對象) */
    public void saveScores(Vector scores) { // Vector
        try {
            rms = RecordStore.openRecordStore(STORE_NAME, true,
                    RecordStore.AUTHMODE_ANY, true);
            // 清空舊數據
            int[] ids = rms.getRecordIds();
            for (int id : ids) rms.deleteRecord(id);
            
            // 寫入新數據
            for (int i = 0; i < scores.size(); i++) {
                Score s = (Score) scores.elementAt(i);
                // 序列化: name#level#score#date
                String line = s.name + "#" + s.level + "#" + s.score + "#" + s.date;
                rms.addRecord(RmsCodec.toBytes(line), 0, line.length());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeQuietly();
        }
    }

    /** 讀取分數列表 */
    public Vector loadScores() {
        Vector result = new Vector();
        try {
            rms = RecordStore.openRecordStore(STORE_NAME, true,
                    RecordStore.AUTHMODE_ANY, true);
            RecordEnumeration enum = rms.enumerateRecords(null, null, false);
            while (enum.hasNextElement()) {
                int id = enum.nextRecordId();
                byte[] data = rms.getRecord(id);
                String line = RmsCodec.toString(data);
                // 解析: name#level#score#date
                String[] parts = split(line, '#');
                if (parts.length == 4) {
                    Score s = new Score();
                    s.name = parts[0];
                    s.level = Integer.parseInt(parts[1]);
                    s.score = Integer.parseInt(parts[2]);
                    s.date = parts[3];
                    result.addElement(s);
                }
            }
            enum.destroy();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeQuietly();
        }
        return result;
    }
    // split 輔助方法省略...
}

關鍵最佳實踐總結

RMS 限制與替代方案

  • 容量上限:總空間通常 100KB-1MB,單條記錄 64KB
  • 無查詢能力:僅支持順序枚舉,無索引/排序/過濾
  • 並發風險:多 MIDlet 同時訪問需協調 (AUTHMODE_ANY)
  • 替代方案:
    • JSR 75 FileConnection API (大容量文件存儲)
    • JSR 169 SQLite (嵌入式關係數據庫,高端設備)
    • 服務端雲存儲 (網絡可用時首選)

掌握 RMS 正確用法,是 J2ME 本地持久化的必修課。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
場景錯誤做法正確做法理由
中文存儲str.getBytes()DataOutputStream.writeUTF()Modified UTF-8 跨平台安全
異常處理忽略 close()finally 塊中 closeQuietly()防止 RecordStore 鎖死/句柄洩漏
頻繁讀寫每次 open/close緩存 RecordStore 引用,批量操作減少閃存擦寫,提升性能
大數據存儲單條記錄存大對象分塊存儲 + 索引記錄單條記錄限制 ~64KB,分塊突破
數據遷移直接修改格式版本號機制 + 兼容舊格式讀取支持舊版本數據平滑升級