背景
一直沒有深入的學習字符集和編碼的知識(現在也沒有深入),今天查閱了一些資料,弄明白了一些事情,本文就簡單記錄一下。
字符集和編碼
字符集是指一些符號組成的集合,編碼是對指定字符集如何表示為字節的一種規則,一個字符集可以由多種編碼。
參考文章:http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html。
.NET支持多少種編碼?默認編碼是什么?
測試程序
1 public static void 打印所有編碼規則總數() 2 { 3 Console.WriteLine(string.Format("系統支持【{0}】條編碼規則。", Encoding.GetEncodings().Count())); 4 } 5 6 public static void 打印默認編碼規則() 7 { 8 Console.WriteLine(string.Format("系統默認編碼規則:【{0}】。", Encoding.Default.EncodingName)); 9 }
輸出結果
注:系統的默認編碼和操作系統的語言環境有關系,我是中文操作系統,所以這里的輸出是:GB2312。
.NET中使用何種編碼表示字符串?
這個問題和源代碼所在的文件的編碼沒有任何關系,文件的格式只是影響開發期間的編程工作,如:采用ASCII編碼的文件不能使用中文變量名。
因為Char的內部表示和Short是一樣的,所以不難想象.NET使用的是Unicode的16位編碼,讓我們測試一下。
測試程序
1 public static void 語言的字符串采用的編碼() 2 { 3 Console.WriteLine("\n***" + System.Reflection.MethodInfo.GetCurrentMethod().Name + "***"); 4 5 string originalString = "hi 段"; 6 7 Console.WriteLine( 8 String.Join( 9 ",", 10 originalString 11 .SelectMany(x => new byte[] { (byte)(x), (byte)(x >> 8) }) 12 .Select(x => Convert.ToString(x, 16)) 13 ) 14 ); 15 16 Console.WriteLine( 17 String.Join( 18 ",", 19 Encoding.Unicode 20 .GetBytes(originalString) 21 .Select(x => Convert.ToString(x, 16)) 22 ) 23 ); 24 25 Console.WriteLine( 26 String.Join( 27 ",", 28 Encoding.UTF8 29 .GetBytes(originalString) 30 .Select(x => Convert.ToString(x, 16)) 31 ) 32 ); 33 34 Console.WriteLine( 35 String.Join( 36 ",", 37 Encoding.UTF32 38 .GetBytes(originalString) 39 .Select(x => Convert.ToString(x, 16)) 40 ) 41 ); 42 }
輸出結果
一些錯誤的編碼使用場景
編碼和解碼使用不同的規則
測試代碼
1 public static void 將string轉換為byte數組和將byte數組轉換為string采用不同的編碼規則() 2 { 3 Console.WriteLine("\n***" + System.Reflection.MethodInfo.GetCurrentMethod().Name + "***"); 4 5 string originalString = "Hello Test, 測試!"; 6 7 byte[] utf8Bytes = Encoding.UTF8.GetBytes(originalString); 8 string errorString = Encoding.ASCII.GetString(utf8Bytes); 9 10 Console.WriteLine("原始字符串:【{0}】。", originalString); 11 Console.WriteLine("用UTF8編碼,用ASCII解碼后的錯誤字符串:【{0}】。", errorString); 12 }
輸出結果
使用的編碼規則對應的字符集不支持字符串擁有的字符
測試程序
1 public static void 將string轉換為byte數組使用了錯誤了編碼規則() 2 { 3 Console.WriteLine("\n***" + System.Reflection.MethodInfo.GetCurrentMethod().Name + "***"); 4 5 string originalString = "Hello Test, 測試!"; 6 7 byte[] asciiBytes = Encoding.ASCII.GetBytes(originalString); 8 string errorString = Encoding.ASCII.GetString(asciiBytes); 9 10 Console.WriteLine("原始字符串:【{0}】。", originalString); 11 Console.WriteLine("用ASCII編碼,用ASCII解碼后的錯誤字符串:【{0}】,因為字符串中包含非ASCII字符。", errorString); 12 }
輸出結果
ANSI在中文操作系統下原來是GB2212
昨晚以為ANSI是采用ASCII編碼,早上經群里的朋友斧正,原來是根據不同的環境會采用不同的編碼,中文操作系統多少是GB2312。
測試程序
1 public static void 讀取包含了ANSI字符的ANSI編碼文件() 2 { 3 Console.WriteLine("\n***" + System.Reflection.MethodInfo.GetCurrentMethod().Name + "***"); 4 5 var file = @"E:\Coding\HappyStudy\EncodingStudy\EncodingStudy\ANSI.txt"; 6 Console.WriteLine("使用GB2312編碼讀取的內容:" + File.ReadAllText(file, Encoding.GetEncoding("GB2312"))); 7 }
如何在不同的編碼規則之間進行轉換呢?
程序中的字符串使用是采用Unicode進行編碼的,我們指的編碼轉換多少是指不同的IO流之間的轉換,簡單的思路是:
- 將“源流”轉換為.NET字符串(Unicode)編碼。
- 將.NET字符串以目標編碼寫入“目標流”。
注:應該有快捷的算法在字節級別直接在兩種編碼規則之間做映射的,這里沒有深究。
能自動識別文件編碼嗎?
為什么.NET沒有提供自動識別文件編碼的功能?估計是沒法支持,現實確實是沒法支持,具體來說是只能支持個別編碼的自動識別,原理參考這篇文章:http://blog.csdn.net/lipeijs3/article/details/5062243。
備注
.NET中處理編碼還是比較舒服的,改天得看看動態語言是如何處理的,等幾天寫一篇Ruby相關的編碼文章。