在 .NET 早期版本(.NET Framework 2.0/3.5)中,內建編碼類別 Encoding.GetEncoding("big5") 僅負責位元組↔字元轉換,不具備繁簡字形轉換功能。若需將 Big5 編碼的繁體中文轉為 GB2312 編碼的簡體中文,必須呼叫 Windows API LCMapString(透過 kernel32.dll)配合 LCMAP_SIMPLIFIED_CHINESE 標誌。本文提供完整可運行的主控台程式範例,支援批次轉換目錄下符合條件的檔案。
LCMapString,傳入 LOCALE_SYSTEM_DEFAULT (0x0804) 與 LCMAP_SIMPLIFIED_CHINESE (0x02000000),將位元組陣列中的繁體字形對應轉換為簡體字形。using System;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;
public class Big5ToGb2312Converter
{
// LCMapStringA: ANSI 版本,配合 byte[] 使用
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true, EntryPoint = "LCMapStringA")]
private static extern int LCMapString(
int Locale,
int dwMapFlags,
byte[] lpSrcStr,
int cchSrc,
byte[] lpDestStr,
int cchDest);
private const int LOCALE_SYSTEM_DEFAULT = 0x0804; // 系統預設地區 (中文環境)
private const int LCMAP_SIMPLIFIED_CHINESE = 0x02000000; // 繁體→簡體
private const int LCMAP_TRADITIONAL_CHINESE = 0x04000000; // 簡體→繁體 (反向)
public static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("用法: Big5ToGb2312Converter.exe <來源目錄> [檔案篩選模式, 預設 *.*]");
Console.WriteLine("範例: Big5ToGb2312Converter.exe D:\\Data *.txt");
return;
}
string sourceDir = args[0];
string pattern = args.Length > 1 ? args[1] : "*.*";
if (!Directory.Exists(sourceDir))
{
Console.WriteLine($"目錄不存在: {sourceDir}");
return;
}
string outputDir = Path.Combine(sourceDir, "conv");
if (!Directory.Exists(outputDir))
Directory.CreateDirectory(outputDir);
string[] files = Directory.GetFiles(sourceDir, pattern);
Console.WriteLine($"找到 {files.Length} 個檔案,開始轉換...");
int success = 0, fail = 0;
foreach (string file in files)
{
try
{
// 1. 以 Big5 讀取
string content;
using (var sr = new StreamReader(file, Encoding.GetEncoding("big5")))
content = sr.ReadToEnd();
// 2. 繁體(Big5字形) → 簡體(GB2312字形)
string converted = ConvertTraditionalToSimplified(content);
// 3. 以 GB2312 寫入
string destFile = Path.Combine(outputDir, Path.GetFileName(file));
using (var sw = new StreamWriter(destFile, false, Encoding.GetEncoding("gb2312")))
sw.Write(converted);
Console.WriteLine($"[OK] {Path.GetFileName(file)}");
success++;
}
catch (Exception ex)
{
Console.WriteLine($"[失敗] {Path.GetFileName(file)}: {ex.Message}");
fail++;
}
}
Console.WriteLine($"\n完成: 成功 {success}, 失敗 {fail}. 輸出目錄: {outputDir}");
}
///
/// 核心轉換邏輯: 字串(繁體字形) -> GB2312位元組 -> LCMapString轉簡體字形 -> 字串
///
private static string ConvertTraditionalToSimplified(string input)
{
// 取得 GB2312 編碼器 (Code Page 936)
Encoding gb2312 = Encoding.GetEncoding(936);
// 字串 -> GB2312 位元組 (此時字形仍為繁體)
byte[] srcBytes = gb2312.GetBytes(input);
byte[] destBytes = new byte[srcBytes.Length]; // 簡體字形通常不超過原長度
// 呼叫 Windows API 轉換字形
// cchSrc = -1 表示以 null 結尾字串處理, 但這裡傳 byte[] 需給實際長度
int result = LCMapString(
LOCALE_SYSTEM_DEFAULT,
LCMAP_SIMPLIFIED_CHINESE,
srcBytes,
srcBytes.Length,
destBytes,
destBytes.Length);
if (result == 0)
{
int err = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(err, "LCMapString 呼叫失敗");
}
// 位元組 -> 字串 (GB2312 解碼, 字形已為簡體)
return gb2312.GetString(destBytes, 0, result); // 使用實際寫入長度
}
}
Encoding.GetEncoding("gb2312"),但用數字代碼頁更明確、效能略高。LCMapStringA (ANSI) 搭配 byte[];若改用 LCMapStringW (Unicode) 需傳 char[] 並設 CharSet = CharSet.Unicode,邏輯相同。SetLastError = true 並檢查返回值為 0 時透過 Marshal.GetLastWin32Error() 取得錯誤碼。Encoding.GetEncoding(936) 需註冊 EncodingProvider(System.Text.Encoding.CodePages 套件),否則會擲回 NotSupportedException。若專案已升級至 .NET Core 3.0 或更新版本,強烈建議改用內建的 System.Text.Encoding 搭配 ChineseConverter (NuGet: Microsoft.ML.Tokenizers 或第三方庫) 或直接使用 System.Globalization.CultureInfo 相關功能,避免 P/Invoke 部署困擾。但若必須維護 .NET Framework 老專案,上述 LCMapString 方案仍是最輕量、零依賴的選擇。
透過 kernel32.dll::LCMapString 配合 LCMAP_SIMPLIFIED_CHINESE 標誌,我們能在不引入額外第三方庫的前提下,可靠地完成 Big5 繁體到 GB2312 簡體的「編碼+字形」雙重轉換。範例程式已包含完整錯誤處理、批次處理與編碼正確性保障,可直接投入生產環境使用。