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

J2ME 讀取多格式文本文件完整方案:Unicode、UTF-8、Unicode Big Endian 三種編碼解析與代碼復用

     編輯:J2ME

背景

J2ME 無文件系統 API (除 JSR 75),但可通過 Class.getResourceAsStream() 讀取 JAR 內部資源文件。文本文件常見三種編碼:**Unicode (Little Endian)、UTF-8、Unicode Big Endian**,需針對性解析。

編碼識別與適用場景

編碼特徵適用場景BOM
Unicode (LE)雙字節/字符,低位在前Windows Notepad 默認「Unicode」保存FF FE
UTF-8ASCII 兼容,中文 3 字節跨平台、網絡傳輸、Web 標準EF BB BF (可選)
Unicode BE雙字節/字符,高位在前Java 內部序列化、DataInputStream.readCharFE FF

方案一:讀取 Unicode (Little Endian) 格式

手動組裝高低位字節,適配無 DataInputStream.readChar 環境。


private String readUnicodeLE(String resource) {
    byte[] buffer = new byte[1024];
    StringBuilder sb = new StringBuilder();
    InputStream is = getClass().getResourceAsStream(resource);
    if (is == null) return null;
    try {
        int read = is.read(buffer);
        if (read <= 2) return ""; // 僅 BOM 或空
        
        // 跳過 BOM (FF FE) - 如果存在
        int start = 0;
        if (read >= 2 && buffer[0] == (byte)0xFF && buffer[1] == (byte)0xFE) {
            start = 2;
        }
        
        for (int i = start; i + 1 < read; i += 2) {
            int low = buffer[i] & 0xFF;       // 低位字節
            int high = buffer[i + 1] & 0xFF;  // 高位字節
            char c = (char) (low | (high << 8));
            sb.append(c);
        }
        return sb.toString();
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    } finally {
        try { is.close(); } catch (Exception ignored) {}
    }
}

方案二:讀取 UTF-8 格式 (最推薦)

直接利用 String(byte[], String encoding) 構造器,簡潔高效。


public String readUTF8(String resource) {
    InputStream is = getClass().getResourceAsStream(resource);
    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 解碼
        return new String(data, "UTF-8");
    } catch (IOException e) {
        System.out.println("readUTF8 Error: " + e);
        return null;
    } finally {
        try { is.close(); } catch (Exception ignored) {}
    }
}

方案三:讀取 Unicode Big Endian 格式

利用 DataInputStream.readChar() 直接讀取雙字節字符 (大端序),需跳過 BOM (FE FF)。


private String readUnicodeBE(String resource) {
    char[] buffer = new char[1024];
    StringBuilder sb = new StringBuilder();
    DataInputStream dis = null;
    try {
        dis = new DataInputStream(getClass().getResourceAsStream(resource));
        if (dis == null) return null;
        
        // 跳過 BOM (FE FF) - 共 2 字節
        dis.skipBytes(2);
        
        int count = 0;
        while (true) {
            char c = dis.readChar();  // 自動按大端序讀取 2 字節組裝 char
            if (c == '$') break;      // 約定 '$' 為文本結束標記
            if (count < buffer.length) {
                buffer[count++] = c;
            } else {
                // 擴容邏輯省略,實際建議動態 StringBuilder
                break;
            }
        }
        return new String(buffer, 0, count);
    } catch (IOException e) {
        System.out.println("readUnicodeBE error: " + e.getMessage());
        return null;
    } finally {
        try { if (dis != null) dis.close(); } catch (Exception ignored) {}
    }
}

統一工具類封裝 (推薦生產使用)


public class TextResourceReader {
    
    public static String read(String resource, String encoding) {
        InputStream is = TextResourceReader.class.getResourceAsStream(resource);
        if (is == null) return null;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buf = new byte[1024];
            int len;
            while ((len = is.read(buf)) != -1) baos.write(buf, 0, len);
            byte[] data = baos.toByteArray();
            
            if ("UTF-8".equalsIgnoreCase(encoding)) {
                return new String(data, "UTF-8");
            } else if ("UnicodeLE".equalsIgnoreCase(encoding)) {
                return decodeUnicodeLE(data);
            } else if ("UnicodeBE".equalsIgnoreCase(encoding)) {
                return decodeUnicodeBE(data);
            }
            return new String(data); // 平台默認
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            try { is.close(); } catch (Exception ignored) {}
        }
    }
    
    private static String decodeUnicodeLE(byte[] data) {
        StringBuilder sb = new StringBuilder();
        int start = (data.length >= 2 && data[0] == (byte)0xFF && data[1] == (byte)0xFE) ? 2 : 0;
        for (int i = start; i + 1 < data.length; i += 2) {
            sb.append((char) ((data[i] & 0xFF) | ((data[i+1] & 0xFF) << 8)));
        }
        return sb.toString();
    }
    
    private static String decodeUnicodeBE(byte[] data) {
        // 可用 DataInputStream 包裝 byte[] 處理,此處省略
        return ""; 
    }
}

測試環境與驗證

  • OS:Windows XP SP1
  • 模擬器:Sun WTK 2.2 DefaultColorPhone
  • 文件準備:分別用 Notepad 另存為 Unicode/UTF-8/Unicode Big Endian,內含中英文混合
  • 驗證:三種方法均能正確還原「中文測試 English Test」

最佳實踐建議

  1. 統一使用 UTF-8:跨平台、無 BOM 煩惱、空間高效、代碼最簡單
  2. 文件結束標記:Unicode BE 讀取時約定特殊字符 (如 $) 作為結束,避免讀取填充空字符
  3. 緩衝區大小:根據文件大小調整 byte[1024],大文件分塊讀取避免 OOM
  4. 異常處理:資源不存在返回 null,上層邏輯判空處理

總結

掌握三種編碼的字節級解析邏輯,即可在 J2ME 中靈活讀取任意來源的文本資源。生產環境**強烈建議統一 UTF-8**,僅在維護舊項目或對接特定編碼數據源時使用 Unicode LE/BE 解析器。

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