UTF-8 為變長編碼,中文字元佔 3 位元組(基本多文種平面 BMP,U+4E00~U+9FFF):
| Unicode 範圍 | UTF-8 位元組結構 | 十六進位範圍 | 說明 |
|---|---|---|---|
| U+4E00 ~ U+9FFF | 1110xxxx 10xxxxxx 10xxxxxx | E4 B8 80 ~ E9 BF BF | 常用漢字區(CJK Unified Ideographs) |
| U+3400 ~ U+4DBF | 1110xxxx 10xxxxxx 10xxxxxx | E3 90 80 ~ E4 B6 BF | 擴展區 A |
| U+20000 ~ U+2A6DF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | F0 A0 80 80 ~ F0 AA 9B 9F | 擴展區 B (4 位元組) |
| U+F900 ~ U+FAFF | 1110xxxx 10xxxxxx 10xxxxxx | EF A4 80 ~ EF AA BF | 相容漢字 |
0xE0 ~ 0xEF(3 位元組字元)或 0xF0 ~ 0xF4(4 位元組字元)0x80 ~ 0xBF(固定模式 10xxxxxx)string filePath = "data.txt";
// 1. 讀取全文(自動處理 BOM、編碼)
string content = File.ReadAllText(filePath, Encoding.UTF8);
// 2. 逐行處理
foreach (string line in File.ReadLines(filePath, Encoding.UTF8))
{
// 處理每行...
}
// 3. 串流處理大檔案(記憶體友善)
using (var reader = new StreamReader(filePath, Encoding.UTF8, true, 4096))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// 處理...
}
}
public static List ExtractChineseWords(byte[] utf8Bytes)
{
var result = new List();
int i = 0;
while (i < utf8Bytes.Length)
{
byte b = utf8Bytes[i];
// ASCII 英數字元 (0x00~0x7F)
if (b < 0x80)
{
i++;
continue;
}
// 3 位元組字元 (0xE0~0xEF) - 可能是中文
if (b >= 0xE0 && b <= 0xEF && i + 2 < utf8Bytes.Length)
{
byte b2 = utf8Bytes[i + 1];
byte b3 = utf8Bytes[i + 2];
// 續位元組檢查
if (b2 >= 0x80 && b2 <= 0xBF && b3 >= 0x80 && b3 <= 0xBF)
{
// 進一步篩選中文範圍:首位元組 0xE4~0xE9
if (b >= 0xE4 && b <= 0xE9)
{
// 提取 3 位元組轉字串
string ch = Encoding.UTF8.GetString(utf8Bytes, i, 3);
result.Add(ch);
}
i += 3;
continue;
}
}
// 4 位元組字元 (0xF0~0xF4) - 擴展區 B
if (b >= 0xF0 && b <= 0xF4 && i + 3 < utf8Bytes.Length)
{
// 類似檢查...
i += 4;
continue;
}
// 非預期位元組,跳過
i++;
}
return result;
}
| 陷阱 | 現象 | 解決方案 |
|---|---|---|
| 無 BOM UTF-8 | Notepad 儲存預設無 BOM,部分舊版工具誤判為 ANSI | 明確指定 Encoding.UTF8,勿依賴自動偵測 |
| BOM 干擾 | 檔案開頭有 EF BB BF,字串處理出現隱形字元 | 使用 Encoding.UTF8.GetString(bytes, 3, bytes.Length - 3) 跳過 BOM |
| 截斷多位元組字元 | 固定長度截取位元組陣列導致半個中文字元 | 使用 StringInfo 或完整字元邊界計算 |
| 混合編碼檔案 | 同一檔案含 UTF-8 與 Big5 區段 | 分區塊讀取、指定對應編碼、或統一轉碼 |
using System.Globalization;
string text = "漢字👨👩👧👦"; // 含 Emoji 字素叢集
var si = new StringInfo(text);
Console.WriteLine($"字元數: {si.LengthInTextElements}"); // 正確計算使用者感知字元數
for (int i = 0; i < si.LengthInTextElements; i++)
{
Console.WriteLine($"字素 {i}: {si.SubstringByTextElements(i, 1)}");
}
UTF-8 中文讀取核心在於 理解變長編碼結構 與 正確使用框架內建編碼類別。手動位元組解析僅適合教學或極特殊場景,生產系統請優先使用 StreamReader、File.ReadAllText 等高階 API,並明確指定 Encoding.UTF8 避免自動偵測失誤。