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

MIDP 實現 ResourceBundle 國際化資源管理:屬性文件讀取與緩存完整方案

     編輯:J2ME

背景與動機

MIDP 標準庫缺失 java.util.ResourceBundle,導致字符串常量硬編碼在代碼中,修改困難、多語言支持無從談起。本文實現一個輕量級 ResourceBundle 類,從 JAR 內部屬性文件加載 key=value 格式資源,提供 getString(int index) 索引式訪問,並演示完整 MIDlet 測試用例。

資源文件格式規範

文件名:index.properties (置於 res/ 目錄,打包進 JAR)

0=ming
1=Java
2=hello
3=world
4=digital
5=hahaha
  • 鍵必須為連續遞增整數字符串 (0, 1, 2...)
  • 值為任意文本,支持中文 (文件需保存為 UTF-8 編碼)
  • 行尾換行符兼容 \n、\r\n、\r

ResourceBundle 核心實現

package fancy.test;

import java.io.*;
import java.util.Vector;

public class ResourceBundle {
    private Vector indexVector;  // 存儲解析後的值
    private String fileName;     // 資源文件路徑 (如 "/index.properties")

    private ResourceBundle() {}  // 防止無參實例化

    public ResourceBundle(String fileName, int size) throws IOException {
        this.fileName = fileName;
        this.indexVector = new Vector(size);
        init();
    }

    private void init() throws IOException {
        readToVector();
    }

    // 從 JAR 獲取資源輸入流
    private InputStream getInputStreamFromFile() {
        return new ResourceBundle().getClass().getResourceAsStream(fileName);
    }

    // 核心解析邏輯:逐字節讀取,按行分割,驗證索引連續性
    private void readToVector() throws IOException {
        InputStream is = getInputStreamFromFile();
        if (is == null) throw new IOException("Resource not found: " + fileName);
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int c = 0;
        int index = 0;
        
        while ((c = is.read()) != -1) {
            if (c == '\n' || c == '\r') {
                String line = baos.toString();
                baos.reset();
                if (line.length() == 0) continue; // 跳過空行
                
                int eqPos = line.indexOf('=');
                if (eqPos == -1) throw new IOException("Invalid format (missing '='): " + line);
                
                String keyStr = line.substring(0, eqPos).trim();
                String value = line.substring(eqPos + 1).trim();
                
                // 驗證索引連續性
                if (!keyStr.equals(String.valueOf(index))) {
                    throw new IOException("Index mismatch: expected " + index + ", got " + keyStr);
                }
                
                indexVector.addElement(value);
                index++;
            } else {
                baos.write(c);
            }
        }
        // 處理文件末尾無換行符的最後一行
        if (baos.size() > 0) {
            String line = baos.toString();
            int eqPos = line.indexOf('=');
            if (eqPos != -1) {
                String keyStr = line.substring(0, eqPos).trim();
                if (keyStr.equals(String.valueOf(index))) {
                    indexVector.addElement(line.substring(eqPos + 1).trim());
                }
            }
        }
        is.close();
    }

    public String getString(int indexID) {
        if (indexID < 0 || indexID >= indexVector.size()) return null;
        return (String) indexVector.elementAt(indexID);
    }
}

MIDlet 測試用例

package fancy.test;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.io.IOException;

public class IndexMIDlet extends MIDlet {
    private ResourceBundle indexBundle;
    private Display display;
    private TextBox box;

    protected void startApp() throws MIDletStateChangeException {
        display = Display.getDisplay(this);
        try {
            indexBundle = new ResourceBundle("/index.properties", 15);
        } catch (IOException e) {
            e.printStackTrace();
        }
        box = new TextBox("ResourceBundle Demo", null, 256, TextField.ANY);
        box.setString(indexBundle.getString(2)); // 顯示 "hello"
        display.setCurrent(box);
    }

    protected void pauseApp() {}
    protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {}
}

關鍵設計點解析

設計決策理由
索引連續性驗證防止屬性文件缺行或順序錯誤導致運行時難以定位的邏輯錯誤
Vector 預分配容量減少動態擴容開銷,適應內存受限環境
逐字節讀取而非 BufferedReaderMIDP 無 BufferedReader,ByteArrayOutputStream 兼容性最佳
UTF-8 編碼假設J2ME 內部字符串為 Unicode,讀取字節流構造 String 時默認平台編碼,建議屬性文件存為 UTF-8 並在讀取時指定編碼 (如有 DataInputStream.readUTF 支持)

擴展建議

  • 增加 getString(String key) 支持字符串鍵值,兼容標準 Java Properties 用法
  • 實現緩存機制:單例模式管理多個 Bundle 實例,避免重複解析
  • 支持多語言:按 Locale 區分文件名 (如 index_zh.properties、index_en.properties)
  • 異常處理增強:區分文件不存在、格式錯誤、索引越界等異常類型

總結

通過 ~100 行代碼實現的 ResourceBundle,解決了 MIDP 缺失標準資源綁定機制的痛點。開發者可將所有 UI 文本、錯誤提示、配置參數外部化到屬性文件,實現「不改代碼、修改文本、支持多語言」的工程化目標。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved