字符串是由一個個字符組成的,每個字符又有一個或多個字節來表示,每個字節又由8個bit位來表示
在C#里 字符串通常由string來聲明,字符由char來聲明,字節由byte來表示,位由bit來表示,具體分析見下面的測試代碼分析:
完整測試代碼:

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Linq.Expressions; 5 using System.Text; 6 using System.Threading.Tasks; 7 using System.IO; 8 namespace CSharpRumenJD 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 15 string unicodestr = "啊?/123"; 16 Console.WriteLine("字符串:" + unicodestr); 17 Console.WriteLine("字符長度:" + unicodestr.Length); 18 Console.WriteLine("Unicode字節長度:" + System.Text.Encoding.Unicode.GetByteCount(unicodestr)); 19 var unicodebytes = System.Text.Encoding.Unicode.GetBytes(unicodestr); 20 Console.WriteLine("gb2312字節長度:" + Encoding.GetEncoding("gb2312").GetByteCount(unicodestr)); 21 var gb2312bytes = System.Text.Encoding.GetEncoding("gb2312").GetBytes(unicodestr); 22 #region 亂碼測試 23 var gb2312tounidecodestr = System.Text.Encoding.Unicode.GetString(gb2312bytes); 24 Console.WriteLine("gb2312bytes轉化成Unicode字符串:" + gb2312tounidecodestr); 25 var gb2312str = System.Text.Encoding.GetEncoding("gb2312").GetString(gb2312bytes); 26 Console.WriteLine("gb2312bytes字符串:" + gb2312str); 27 #endregion 28 #region 打印二進制數據 29 int capacity = gb2312bytes.Length * 8; 30 StringBuilder sb = new StringBuilder(capacity); 31 for (int i = 0; i < gb2312bytes.Length; i++) 32 { 33 sb.Append(gb2312bytes[i] + ":" + Convert.ToString(gb2312bytes[i], 2).PadLeft(8, '0') + "|"); 34 } 35 Console.WriteLine(sb.ToString().TrimEnd('|')); 36 #endregion 37 StreamWriter sw = new StreamWriter("1.txt", false, System.Text.Encoding.Unicode); 38 sw.Write(unicodestr); 39 sw.Close(); 40 StreamWriter sw1 = new StreamWriter("2.txt", false, Encoding.GetEncoding("gb2312")); 41 sw1.Write(unicodestr); 42 sw1.Close(); 43 Console.ReadKey(); 44 } 45 } 46 }
測試結果:
通過測試結果可以看到同樣一個字符串,
通過Unicode編碼獲取的字節長度為12,通過GB2312獲取的字節長度為7,
而且使用Unicode去把GB2312編碼的的字節數組轉化成字符串時出現亂碼問題,使用GB2312的編碼方式把GB2312編碼的字節數組轉化成字符串時沒有任何問題的,
疑問一:為什么兩種編碼方式得到的字節長度不同呢?
Unicode碼:Unicode碼也是一種國際標准編碼,Unicode目前普遍采用的是UCS-2,它用兩個字節來編碼一個字符(多虧了ohmygirl的指點),C#中的Unicode默認使用UTF-16編碼格式,所以上面的字符串的字節長度為12,
GB2312編碼是ANSI編碼中的一個分支,在使用 ANSI 編碼支持多種語言階段,每個字符使用一個字節或多個字節來表示(MBCS),因此,這種方式存放的字符也被稱作多字節字符。比如,"啊?/123"長度為7個字節,每個漢字占2個字節,每個英文和數字字符占1個字節,
字符與編碼的發展
從計算機對多國語言的支持角度看,大致可以分為三個階段:
|
系統內碼 |
說明 |
系統 |
階段一 |
ASCII |
計算機剛開始只支持英語,其它語言不能夠在計算機上存儲和顯示。 |
英文 DOS |
階段二 |
ANSI編碼 |
為使計算機支持更多語言,通常使用 0x80~0xFF 范圍的 2 個字節來表示 1 個字符。比如:漢字 '中' 在中文操作系統中,使用 [0xD6,0xD0] 這兩個字節存儲。 |
中文 DOS,中文 Windows 95/98,日文 Windows 95/98 |
階段三 |
UNICODE |
為了使國際間信息交流更加方便,國際組織制定了 UNICODE 字符集,為各種語言中的每一個字符設定了統一並且唯一的數字編號,以滿足跨語言、跨平台進行文本轉換、處理的要求。 |
Windows NT/2000/XP,Linux,Java |
疑問二:最后一行的十進制數字代表什么呢?
因為字節數組是由GB2312編碼格式得到的,所以需要先了解GB2312的處理方式,在使用GB2312的程序中,每個漢字及符號以兩個字節來表示。第一個字節稱為“高位字節”(也稱“區字節)”,第二個字節稱為“低位字節”(也稱“位字節”),“高位字節”使用了0xA1-0xF7(把01-87區的區號加上0xA0),“低位字節”使用了0xA1-0xFE(把01-94加上 0xA0),其中0xA0轉化成10進制數字就是160,“啊”字是GB2312字符集的第一個漢字,它的區號16,位號01,則區位碼是1601,
所以高位字節碼為0xA0+16即160+16=176,低位字節碼0xA0+01即160+1=161,正好和吻合,而剩下的五個十進制數字和啊字后面的五個字符個數相符,經查:
疑問三:為什么生成的文本文件大小和字節不一致?
從下圖可以看到GB2312編碼格式生成的文件大小為7字節,和控制台打印出來的一致,而Unicode編碼格式生成的文件為14字節,比控制台打印出來的字節長度真真的大了2個字節,不知道如何解釋這個現象
參考資料: