【轉自:https://www.cnblogs.com/IPrograming/archive/2012/10/13/CSharp_Socket_3.html】 html
在網絡通訊中,不少狀況下:好比說QQ聊天,通信雙方直接傳遞的都是字符信息。可是字符信息並不可以直接經過網絡傳輸,這些字符集必須先轉換成一個字節序列後纔可以在網絡中傳輸,因而這裏就產生了編碼和解碼的概念:算法
- 將字符序列轉換爲字節序列的過程稱之爲:編碼
- 將編碼的字節序列轉換爲字符序列的過程稱之爲:解碼
例如:對於Unicode字符來講,編碼是指將一組Unicode字符轉換爲一個字節序列的過程,解碼就是講一個編碼字節序列轉換爲一組Unicode字符。數組
字符集(Charset):是一個系統支持的全部抽象字符的集合。字符是各類文字和符號的總稱,包括各國家文字、標點符號、圖形符號、數字等。常見的編碼方式主要有一下三種:網絡
ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼)是基於拉丁字母的一套電腦編碼系統。它主要用於顯示現代英語,而其擴展版本EASCII則能夠勉強顯示其餘西歐語言。它是現今最通用的單字節編碼系統(可是有被Unicode追上的跡象),並等同於國際標準ISO/IEC 646。ide
因爲ASCII字符集是針對英語設計的,當處理漢字等其餘非拉丁語系的字符時,這種編碼就不能適用了(由於適用128個字符表示英文是徹底足夠的,可是用了表示中文就遠遠不夠了)。爲了解決這個問題,不一樣的國加和地區制定了本身編碼標準。中國通常適用國標碼,經常使用的有GB2312-1980編碼和GB183030-2000編碼,其中GB183030-2000編碼漢字更多,是中國計算機系統必須遵循的基礎性標準之一。函數
因爲每一個國家、語系都擁有獨立的編碼方式,同一個二進制數字能夠被解釋成不一樣的字符,所以要想打開一個文本文件,就必須知道它的編碼方式,不然就可能出現亂碼。爲了使用國際信息交流更加方便,非營利機構統一碼聯盟制定和標準化了Unicode字符集。使用16位的編碼空間。也就是每一個字符佔用2個字節。這樣理論上一共最多能夠表示216(即65536)個字符。基本知足各類語言的使用。實際上當前版本的統一碼並未徹底使用這16位編碼,而是保留了大量空間以做爲特殊使用或未來擴展。
學習
Unicode的實現方式不一樣於編碼方式。一個字符的Unicode編碼是肯定的。可是在實際傳輸過程當中,因爲不一樣系統平臺的設計不必定一致,以及出於節省空間的目的(例如:在C#中字符默認都是Unicode碼,即一個英文字符佔兩個字節,一個漢字也是兩個字節,這對於能適應ASCII字符集來表示的字符來講比較顯得浪費。),對Unicode編碼的實現方式有所不一樣。Unicode的實現方式稱爲Unicode轉換格式(Unicode Transformation Format,簡稱UTF)。目前流行和UFT格式包括UTF-八、UTF16和UTF-32。ui
其中,UTF-8編碼是互聯網上使用最普遍的一種UTF格式,這是一種變長編碼,它將基本7位ASCII字符仍用7位編碼表示,佔用一個字節(首位補0)。而遇到與其餘Unicode字符混合的狀況,將按必定算法轉換,每一個字符使用1-3個字節編碼,並利用首位爲0或1進行識別。這樣對以7位ASCII字符爲主的西文文檔就大大節省了編碼長度。UTF-8是與字節順序無關的,它的字節順序在全部系統中都是同樣的,所以這種編碼可使排序變得很容易。編碼
在C#語言中對於不一樣編碼和Unicode之間的轉換使用位於System.Text命名空間中的Encoding類。經過這個類咱們能夠爲不一樣字符集直接進行轉換以及各個字符集的相關信息 。spa
咱們經過調用Encoding類的GetEncodings()方法獲取包含全部編碼的數組,經過數組元素爲EncodingInfo類,經過數組內的元素能夠得到各類類型編碼的信息。例如咱們能夠經過下面的代碼獲取主機上全部編碼的信息:
//獲取系統全部編碼名稱及其描述信息 EncodingInfo[] allEncoding = Encoding.GetEncodings(); foreach (EncodingInfo encoding in allEncoding) { Console.WriteLine("編碼標識符:{0,-10}編碼名稱:{1,-12}編碼說明:{2}", encoding.CodePage, encoding.Name, encoding.DisplayName); }
運行以下:
Encoding類提供了經常使用的字符集編碼能夠直接經過調用屬性獲取:UTF-8,ASCII等屬性,也能夠經過調用GetEncoding(+4重載)方法直接獲取指定的字符集編碼對象。例如,下面的代碼:
//獲取指定的編碼描述信息 Encoding gb18030Encoding = Encoding.GetEncoding("GB18030"); Encoding asciiEncoding = Encoding.ASCII; Console.WriteLine("編碼標識符:{0,-10}編碼名稱:{1,-12}編碼說明:{2}", gb18030Encoding.CodePage, gb18030Encoding.HeaderName, gb18030Encoding.EncodingName); Console.WriteLine("編碼標識符:{0,-10}編碼名稱:{1,-12}編碼說明:{2}", asciiEncoding.CodePage, asciiEncoding.HeaderName, asciiEncoding.EncodingName);
運行以下:
//不一樣編碼之間的轉換 string GB18030String = "你好!晴天豬"; Console.WriteLine("須要轉換的字符串:{0}", GB18030String); #region 對字符串進行GB18030格式編碼 //獲取編碼器 Encoding gb18030Encoding = Encoding.GetEncoding("GB18030"); //將字符串轉換爲char類型數組 char[] chars = GB18030String.ToCharArray(); //獲取編碼爲字節序列後的字節數組長度 int buffLength = gb18030Encoding.GetByteCount(chars, 0, chars.Length); //根據獲取的字節長度聲明數組,存儲編碼後的字節 byte[] gb18030Buffer = new byte[buffLength]; //獲取GB18030編碼的字節序列 gb18030Buffer = gb18030Encoding.GetBytes(chars, 0, chars.Length); Console.WriteLine("GB18030編碼的字節序列:{0}", BitConverter.ToString(gb18030Buffer)); //將GB18030編碼的字節序列轉換成UTF-8編碼的字節序列 byte[] unicodeBuffer = Encoding.Convert(gb18030Encoding, Encoding.UTF8, gb18030Buffer); Console.WriteLine("轉換爲UTF-8編碼字節序列:{0}", BitConverter.ToString(unicodeBuffer)); #endregion #region 將GB18030編碼轉換爲UTF-8編碼 //獲取UTF-8解碼器 Decoder utf8Decoder = Encoding.UTF8.GetDecoder(); //獲取解碼爲字符後字符數組的長度 int utfChartsLength = utf8Decoder.GetCharCount(unicodeBuffer, 0, unicodeBuffer.Length, true); //根據獲取解碼後的長度建立char數組 char[] utfChart = new char[utfChartsLength]; //將UTF-8編碼的字節序列轉換爲字符串 utf8Decoder.GetChars(unicodeBuffer, 0, unicodeBuffer.Length, utfChart, 0); StringBuilder strBuilder = new StringBuilder(); foreach (char ca in utfChart) { strBuilder.Append(ca); } Console.WriteLine("UTF-8的字符序列解碼:{0}", strBuilder.ToString());
運行程序:
在C#中爲咱們提供了Encoder和Decoder類,分別對字符進行編碼和對字節序列進行解碼的兩個類。經過使用它們,咱們能夠很方便進行對字符和字節序列進行編碼和解碼操做。因爲它們的構造函數都是protected級別的,須要使用 Encoding 實現的 GetEncoder 方法才能獲取到它們的實例對象。下面咱們經過一個Windows Forms示例程序來了解和學習如何使用這兩個類,編碼和解碼的主要代碼以下:
/// <summary> /// 獲取字符串編碼以後的bytes數組 /// </summary> /// <param name="codeType">編碼類型名稱</param> /// <param name="strCode">將被編碼的字符串</param> /// <returns></returns> private byte[] GetEncodeBeforeBuffer(string codeType,string strCode) { //根據編碼類型構造該類型編碼的編碼器的實例 Encoder encoder = Encoding.GetEncoding(codeType).GetEncoder(); char[] chars = strCode.ToCharArray(); //根據獲取對字符進行編碼所產生的字節數來建立一個byte數組 byte[] bytes = new byte[encoder.GetByteCount(chars, 0, chars.Length, true)]; //將字符寫入到byte數組中 encoder.GetBytes(chars, 0, chars.Length, bytes, 0, true); return bytes; } /// <summary> ///獲取字符串解碼以後的字符串 /// </summary> /// <param name="codeType">編碼格式</param> /// <param name="byteCode">編碼的字節數組</param> /// <returns></returns> private string GetDecodeBeforeText(string codeType, byte[] byteCode) { //根據編碼類型構造該類型編碼的解碼器的實例 Decoder decoder = Encoding.GetEncoding(codeType).GetDecoder(); //計算對字節序列(從指定字節數組開始)進行解碼所產生的字符數 char[] chars = new char[decoder.GetCharCount(byteCode, 0, byteCode.Length,true)]; //根據獲取的解碼所產生的字節數來建立一個char數組 int charLen = decoder.GetChars(byteCode, 0, byteCode.Length, chars, 0); StringBuilder strResult = new StringBuilder(); foreach (char c in chars) { strResult = strResult.Append(c.ToString()); } return strResult.ToString(); }
運行程序: