字元編碼是資訊交換基石。Java 內部使用 UTF-16 (char 2 位元組),但 I/O 涉及多種編碼轉換。本文系統整理主流編碼技術特點、轉換原理與 Java 處理實務。
| 編碼 | 位元寬度 | 涵蓋範圍 | 技術特點 | 適用場景 |
|---|---|---|---|---|
| ASCII | 7-bit (1 byte) | 128 字元 | 控制碼 + 英文大小寫 + 數字 + 符號 | 早期系統、協定基礎 |
| ISO-8859-1 (Latin-1) | 8-bit (1 byte) | 256 字元 | ASCII 擴展 + 西歐語言附加符號 | 舊版 Web、HTTP 預設 |
| Unicode (UCS-2/UTF-16) | 16-bit (2 bytes) | BMP (65536字元) | 固定長度,Java char/內部預設 | 記憶體內部處理 |
| UTF-8 | 變長 1-4 bytes | 全 Unicode (111萬+) | ASCII 相容 (1 byte)、多語言混排節省空間 | Web 標準、檔案儲存、網路傳輸 |
| GB2312 | 雙位元組 | 6763 漢字 + 682 符號 | 高位 0xA1-0xF7,低位 0xA1-0xFE,一級漢字 0xB0+ | 中文舊系統、中國大陸標準 |
| GBK/GB18030 | 雙/四位元組 | 擴展漢字 + 少數民族字 | GB2312 超集,GB18030 為國家強制標準 | 中文現代系統 |
位元組結構:
0xxxxxxx (U+0000 ~ U+007F,ASCII 相容)110xxxxx 10xxxxxx (U+0080 ~ U+07FF)1110xxxx 10xxxxxx 10xxxxxx (U+0800 ~ U+FFFF,含中日韓)11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (U+10000 ~ U+10FFFF,Emoji、罕用字)範例:
'A' (U+0041) → 41 (1 byte)'中' (U+4E2D) → E4 B8 AD (3 bytes)'😀' (U+1F600) → F0 9F 98 80 (4 bytes)
// 解碼: bytes → String (指定編碼)
String str = new String(bytes, StandardCharsets.UTF_8);
String str = new String(bytes, "GBK"); // 繁體/簡體混合常用
// 編碼: String → bytes (指定編碼)
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
byte[] bytes = str.getBytes("GB2312");
// 讀取 UTF-8 檔案
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) { ... }
}
// 寫入 GBK 檔案
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(file), "GBK"))) {
writer.write("中文內容");
}
Charset utf8 = StandardCharsets.UTF_8;
CharsetEncoder encoder = utf8.newEncoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.replaceWith("?");
ByteBuffer bb = encoder.encode(CharBuffer.wrap("測試"));
| 現象 | 原因 | 解決 |
|---|---|---|
| 中文顯示 ??? 或 | 編碼不支援該字元 (如 ISO-8859-1 讀中文) | 指定正確編碼 (UTF-8/GBK) |
| 中文變亂碼 (??) | 雙重編碼/解碼錯誤 (UTF-8 bytes 用 GBK 解碼) | 統一編碼、檢查傳輸鏈路 |
| 檔案讀取首行有隱形字元 | UTF-8 BOM (EF BB BF) | 用 BOMInputStream 或手動跳過 |
| 資料庫存取亂碼 | JDBC URL 缺 characterEncoding、DB/表/欄編碼不一致 | URL 加 useUnicode=true&characterEncoding=UTF-8 |
| 網頁表單提交亂碼 | 頁面 encoding、form accept-charset、Server.xml URIEncoding 不一 | 全鏈路 UTF-8、Tomcat 設 URIEncoding=UTF-8 |
StandardCharsets.UTF_8 等常數避免拼字錯誤、保證平台支援REPLACE (替換 ?)、IGNORE (忽略)、REPORT (拋異常) 視業務而定掌握編碼本質、Java API 正確用法、全鏈路一致性,是解決亂碼問題的根本之道。