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

C# 文字檔編碼自動偵測:BOM 掃描與 StreamReader 正確讀寫指南

     編輯:關於C語言

前言

讀寫中文文字檔最常見的亂碼原因是:**編碼不匹配**。`StreamReader`/`StreamWriter` 預設使用 `Encoding.Default`(繁中系統為 Big5,簡中為 GB2312),而檔案實際可能是 UTF-8、UTF-16 LE/BE。本文提供一個 `TxtFileEncoding` 工具類,透過掃描檔案開頭的 **BOM (Byte Order Mark)** 自動判斷編碼,確保讀寫正確無誤。

BOM 對照表

編碼BOM 位元組 (Hex)說明
UTF-8EF BB BF最常見,建議預設儲存格式
UTF-16 LE (Unicode)FF FEWindows 記事本「Unicode」預設
UTF-16 BE (BigEndianUnicode)FE FF網路序/大端序
UTF-32 LEFF FE 00 00極少用
UTF-32 BE00 00 FE FF極少用
GB2312 / Big5 / ASCII無 BOM無法自動偵測,需指定預設編碼

TxtFileEncoding 核心實作

using System;
using System.IO;
using System.Text;

namespace Farproc.Text
{
    public static class TxtFileEncoding
    {
        /// 
        /// 取得檔案編碼。無 BOM 時回傳 defaultEncoding(預設 Encoding.Default)。
        /// 
        public static Encoding GetEncoding(string fileName, Encoding defaultEncoding = null)
        {
            defaultEncoding ??= Encoding.Default;
            using var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
            return GetEncoding(fs, defaultEncoding);
        }

        /// 
        /// 取得資料流編碼(不關閉 Stream)。
        /// 
        public static Encoding GetEncoding(Stream stream, Encoding defaultEncoding = null)
        {
            defaultEncoding ??= Encoding.Default;
            if (stream == null || stream.Length < 2) return defaultEncoding;

            long origPos = stream.Position;
            stream.Seek(0, SeekOrigin.Begin);
            
            // 讀取前 4 位元組
            int b1 = stream.ReadByte();
            int b2 = stream.ReadByte();
            int b3 = stream.Length >= 3 ? stream.ReadByte() : -1;
            int b4 = stream.Length >= 4 ? stream.ReadByte() : -1;
            
            stream.Seek(origPos, SeekOrigin.Begin); // 還原位置

            // 依序判斷(優先匹配較長 BOM)
            if (b1 == 0xEF && b2 == 0xBB && b3 == 0xBF) return Encoding.UTF8;
            if (b1 == 0xFF && b2 == 0xFE && b3 != 0xFF) return Encoding.Unicode; // UTF-16 LE
            if (b1 == 0xFE && b2 == 0xFF) return Encoding.BigEndianUnicode;       // UTF-16 BE
            if (b1 == 0xFF && b2 == 0xFE && b3 == 0x00 && b4 == 0x00) return Encoding.UTF32; // UTF-32 LE
            if (b1 == 0x00 && b2 == 0x00 && b3 == 0xFE && b4 == 0xFF) return Encoding.GetEncoding("UTF-32BE"); // UTF-32 BE

            return defaultEncoding; // 無 BOM:GB2312/Big5/ASCII 等
        }
    }
}

使用範例:正確讀寫流程

string file = @"E:\data.txt";

// 1. 寫入:明確指定編碼(建議 UTF-8)
using (var sw = new StreamWriter(file, false, Encoding.UTF8))
{
    sw.WriteLine("這是測試內容");
    sw.WriteLine("Second line");
}

// 2. 讀取:自動偵測編碼
Encoding enc = TxtFileEncoding.GetEncoding(file, Encoding.GetEncoding("GB2312")); // 簡中環境預設 GB2312
Console.WriteLine($"偵測編碼: {enc.EncodingName}");

using (var sr = new StreamReader(file, enc))
{
    string content = sr.ReadToEnd();
    Console.WriteLine(content);
}

進階議題

1. 無 BOM 檔案的編碼偵測

GB2312、Big5、ASCII、UTF-8 (無 BOM) 皆無 BOM。可採用以下策略:

  • 統一規範:專案強制儲存為 UTF-8 **含 BOM**(`Encoding.UTF8` 預設寫入 BOM),消除歧義。
  • 啟發式偵測:使用 Ude.NetStandard (Mozilla Universal Charset Detector 移植版) 或 NTextCat 進行統計分析偵測。
  • 約定俗成:特定目錄/副檔名約定編碼(如 `.csv` 預設 Big5/GB2312)。

2. .NET Core / .NET 5+ 變化

  • `StreamReader` 建構子 `new StreamReader(path, true)` 可**自動偵測 UTF-8/UTF-16/UTF-32 BOM**,但**無法取得偵測到的編碼物件**(`CurrentEncoding` 只有在讀取後才正確)。
  • 若需明確編碼物件,仍需自行實作 BOM 掃描(如本文工具類)。
  • `Encoding.Default` 在 .NET Core 固定回傳 **UTF-8**,不再隨系統地區變化,跨平台一致性大幅提升。

3. 大檔案效能考量

  • 本工具僅讀取前 4 Bytes,**常數時間 O(1)**,對大檔案零負擔。
  • 讀取大檔案內容時,建議 `File.ReadLines` (延遲枚舉) 替代 `ReadToEnd`,避免記憶體壓力。

4. 寫入時是否加入 BOM

編碼StreamWriter 預設行為建議
UTF-8**寫入 BOM** (EF BB BF)保留,利於自動偵測
UTF-16 LE/BE寫入 BOM保留
GB2312/Big5無 BOM不適用

若需**不寫入 UTF-8 BOM**,使用 `new UTF8Encoding(false)`(`encoderShouldEmitUTF8Identifier=false`)。

總結

**BOM 掃描是最輕量、最可靠的編碼自動偵測手段**。建立專案編碼規範(統一 UTF-8+BOM)搭配 `TxtFileEncoding` 工具類,可徹底解決中文亂碼問題。現代 .NET 環境下,`Encoding.Default` 已統一為 UTF-8,跨平台編碼坑點大幅減少,但舊檔案遷移、異構系統整合時,本工具仍具高實用價值。

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