J2ME 無文件系統 API (除 JSR 75),但可通過 Class.getResourceAsStream() 讀取 JAR 內部資源文件。文本文件常見三種編碼:**Unicode (Little Endian)、UTF-8、Unicode Big Endian**,需針對性解析。
| 編碼 | 特徵 | 適用場景 | BOM |
|---|---|---|---|
| Unicode (LE) | 雙字節/字符,低位在前 | Windows Notepad 默認「Unicode」保存 | FF FE |
| UTF-8 | ASCII 兼容,中文 3 字節 | 跨平台、網絡傳輸、Web 標準 | EF BB BF (可選) |
| Unicode BE | 雙字節/字符,高位在前 | Java 內部序列化、DataInputStream.readChar | FE FF |
手動組裝高低位字節,適配無 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) {}
}
}
直接利用 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) {}
}
}
利用 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 "";
}
}
$) 作為結束,避免讀取填充空字符byte[1024],大文件分塊讀取避免 OOMnull,上層邏輯判空處理掌握三種編碼的字節級解析邏輯,即可在 J2ME 中靈活讀取任意來源的文本資源。生產環境**強烈建議統一 UTF-8**,僅在維護舊項目或對接特定編碼數據源時使用 Unicode LE/BE 解析器。