在網(wǎng)絡通信中,很多情況下:比如說QQ聊天,通訊雙方直接傳遞的都是字符信息。但是字符信息并不能夠直接通過網(wǎng)絡傳輸,這些字符集必須先轉(zhuǎn)換成一個字節(jié)序列后才能夠在網(wǎng)絡中傳輸,于是這里就產(chǎn)生了編碼和解碼的概念:
例如:對于Unicode字符來說,編碼是指將一組Unicode字符轉(zhuǎn)換為一個字節(jié)序列的過程,解碼就是講一個編碼字節(jié)序列轉(zhuǎn)換為一組Unicode字符。 目錄索引: 1.4 UTF(通用轉(zhuǎn)換格式)的出現(xiàn)
字符編碼基礎知識字符集(Charset):是一個系統(tǒng)支持的所有抽象字符的集合。字符是各種文字和符號的總稱,包括各國家文字、標點符號、圖形符號、數(shù)字等。常見的編碼方式主要有一下三種: 1.1 ASCII字符集ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼)是基于拉丁字母的一套電腦編碼系統(tǒng)。它主要用于顯示現(xiàn)代英語,而其擴展版本EASCII則可以勉強顯示其他西歐語言。它是現(xiàn)今最通用的單字節(jié)編碼系統(tǒng)(但是有被Unicode追上的跡象),并等同于國際標準ISO/IEC 646。 1.2 非ASCII字符集由于ASCII字符集是針對英語設計的,當處理漢字等其他非拉丁語系的字符時,這種編碼就不能適用了(因為適用128個字符表示英文是完全足夠的,但是用了表示中文就遠遠不夠了)。為了解決這個問題,不同的國加和地區(qū)制定了自己編碼標準。中國一般適用國標碼,常用的有GB2312-1980編碼和GB183030-2000編碼,其中GB183030-2000編碼漢字更多,是中國計算機系統(tǒng)必須遵循的基礎性標準之一。 1.3 Unicode字符集 由于每個國家、語系都擁有獨立的編碼方式,同一個二進制數(shù)字可以被解釋成不同的字符,因此要想打開一個文本文件,就必須知道它的編碼方式,否則就可能出現(xiàn)亂碼。為了使用國際信息交流更加方便,非營利機構統(tǒng)一碼聯(lián)盟制定和標準化了Unicode字符集。使用16位的編碼空間。也就是每個字符占用2個字節(jié)。這樣理論上一共最多可以表示216(即65536)個字符?;緷M足各種語言的使用。實際上當前版本的統(tǒng)一碼并未完全使用這16位編碼,而是保留了大量空間以作為特殊使用或?qū)頂U展。 1.4 UTF(通用轉(zhuǎn)換格式)的出現(xiàn)Unicode的實現(xiàn)方式不同于編碼方式。一個字符的Unicode編碼是確定的。但是在實際傳輸過程中,由于不同系統(tǒng)平臺的設計不一定一致,以及出于節(jié)省空間的目的(例如:在C#中字符默認都是Unicode碼,即一個英文字符占兩個字節(jié),一個漢字也是兩個字節(jié),這對于能適應ASCII字符集來表示的字符來說比較顯得浪費。),對Unicode編碼的實現(xiàn)方式有所不同。Unicode的實現(xiàn)方式稱為Unicode轉(zhuǎn)換格式(Unicode Transformation Format,簡稱UTF)。目前流行和UFT格式包括UTF-8、UTF16和UTF-32。 其中,UTF-8編碼是互聯(lián)網(wǎng)上使用最廣泛的一種UTF格式,這是一種變長編碼,它將基本7位ASCII字符仍用7位編碼表示,占用一個字節(jié)(首位補0)。而遇到與其他Unicode字符混合的情況,將按一定算法轉(zhuǎn)換,每個字符使用1-3個字節(jié)編碼,并利用首位為0或1進行識別。這樣對以7位ASCII字符為主的西文文檔就大大節(jié)省了編碼長度。UTF-8是與字節(jié)順序無關的,它的字節(jié)順序在所有系統(tǒng)中都是一樣的,因此這種編碼可以使排序變得很容易。
2.C#中不同編碼和Unicode之間的轉(zhuǎn)換在C#語言中對于不同編碼和Unicode之間的轉(zhuǎn)換使用位于System.Text命名空間中的Encoding類。通過這個類我們可以為不同字符集直接進行轉(zhuǎn)換以及各個字符集的相關信息 。 2.1 獲取系統(tǒng)所有編碼信息我們通過調(diào)用Encoding類的GetEncodings()方法獲取包含所有編碼的數(shù)組,通過數(shù)組元素為EncodingInfo類,通過數(shù)組內(nèi)的元素可以獲得各種類型編碼的信息。例如我們可以通過下面的代碼獲取主機上所有編碼的信息: 1 //獲取系統(tǒng)所有編碼名稱及其描述信息 2 EncodingInfo[] allEncoding = Encoding.GetEncodings(); 3 foreach (EncodingInfo encoding in allEncoding) 4 { 5 Console.WriteLine("編碼標識符:{0,-10}編碼名稱:{1,-12}編碼說明:{2}", encoding.CodePage, encoding.Name, encoding.DisplayName); 6 } 運行如下:
2.2 獲取指定的編碼信息Encoding類提供了常用的字符集編碼可以直接通過調(diào)用屬性獲?。篣TF-8,ASCII等屬性,也可以通過調(diào)用GetEncoding(+4重載)方法直接獲取指定的字符集編碼對象。例如,下面的代碼: 1 //獲取指定的編碼描述信息 2 Encoding gb18030Encoding = Encoding.GetEncoding("GB18030"); 3 Encoding asciiEncoding = Encoding.ASCII; 4 Console.WriteLine("編碼標識符:{0,-10}編碼名稱:{1,-12}編碼說明:{2}", gb18030Encoding.CodePage, gb18030Encoding.HeaderName, gb18030Encoding.EncodingName); 5 Console.WriteLine("編碼標識符:{0,-10}編碼名稱:{1,-12}編碼說明:{2}", asciiEncoding.CodePage, asciiEncoding.HeaderName, asciiEncoding.EncodingName);
運行如下:
2.3在不同編碼之間進行轉(zhuǎn)換我們可以可以通過利用Encoding.Convert(+2重載)直接將字節(jié)數(shù)組從一種編碼轉(zhuǎn)換為另一種編碼。下面我們同樣通過一個示例代碼來學習如何對不同編碼的字節(jié)序列進行轉(zhuǎn)換。下面的示例程序,為了清楚的演示如何使用,可能代碼比較冗余(代碼中包含解碼和編碼部分,在隨后會給出相應示例),實際的應用中我們可以根據(jù)自己的情況進行適當?shù)膶Ψ椒ǔ橄螅貥?,提升程序的可讀性和效率。代碼如下: View Code
1 //不同編碼之間的轉(zhuǎn)換 2 string GB18030String = "你好!晴天豬"; 3 Console.WriteLine("需要轉(zhuǎn)換的字符串:{0}", GB18030String); 4 #region 對字符串進行GB18030格式編碼 5 6 //獲取編碼器 7 Encoding gb18030Encoding = Encoding.GetEncoding("GB18030"); 8 //將字符串轉(zhuǎn)換為char類型數(shù)組 9 char[] chars = GB18030String.ToCharArray(); 10 //獲取編碼為字節(jié)序列后的字節(jié)數(shù)組長度 11 int buffLength = gb18030Encoding.GetByteCount(chars, 0, chars.Length); 12 //根據(jù)獲取的字節(jié)長度聲明數(shù)組,存儲編碼后的字節(jié) 13 byte[] gb18030Buffer = new byte[buffLength]; 14 //獲取GB18030編碼的字節(jié)序列 15 gb18030Buffer = gb18030Encoding.GetBytes(chars, 0, chars.Length); 16 Console.WriteLine("GB18030編碼的字節(jié)序列:{0}", BitConverter.ToString(gb18030Buffer)); 17 //將GB18030編碼的字節(jié)序列轉(zhuǎn)換成UTF-8編碼的字節(jié)序列 18 byte[] unicodeBuffer = Encoding.Convert(gb18030Encoding, Encoding.UTF8, gb18030Buffer); 19 Console.WriteLine("轉(zhuǎn)換為UTF-8編碼字節(jié)序列:{0}", BitConverter.ToString(unicodeBuffer)); 20 21 #endregion 22 23 #region 將GB18030編碼轉(zhuǎn)換為UTF-8編碼 24 25 //獲取UTF-8解碼器 26 Decoder utf8Decoder = Encoding.UTF8.GetDecoder(); 27 //獲取解碼為字符后字符數(shù)組的長度 28 int utfChartsLength = utf8Decoder.GetCharCount(unicodeBuffer, 0, unicodeBuffer.Length, true); 29 //根據(jù)獲取解碼后的長度創(chuàng)建char數(shù)組 30 char[] utfChart = new char[utfChartsLength]; 31 //將UTF-8編碼的字節(jié)序列轉(zhuǎn)換為字符串 32 utf8Decoder.GetChars(unicodeBuffer, 0, unicodeBuffer.Length, utfChart, 0); 33 34 StringBuilder strBuilder = new StringBuilder(); 35 foreach (char ca in utfChart) 36 { 37 strBuilder.Append(ca); 38 } 39 Console.WriteLine("UTF-8的字符序列解碼:{0}", strBuilder.ToString()); 運行程序:
3.C#編碼和解碼在C#中為我們提供了Encoder和Decoder類,分別對字符進行編碼和對字節(jié)序列進行解碼的兩個類。通過使用它們,我們可以很方便進行對字符和字節(jié)序列進行編碼和解碼操作。由于它們的構造函數(shù)都是protected級別的,需要使用 Encoding 實現(xiàn)的 GetEncoder 方法才能獲取到它們的實例對象。下面我們通過一個Windows Forms示例程序來了解和學習如何使用這兩個類,編碼和解碼的主要代碼如下: View Code
1 /// <summary> 2 /// 獲取字符串編碼之后的bytes數(shù)組 3 /// </summary> 4 /// <param name="codeType">編碼類型名稱</param> 5 /// <param name="strCode">將被編碼的字符串</param> 6 /// <returns></returns> 7 private byte[] GetEncodeBeforeBuffer(string codeType,string strCode) 8 { 9 //根據(jù)編碼類型構造該類型編碼的編碼器的實例 10 Encoder encoder = Encoding.GetEncoding(codeType).GetEncoder(); 11 12 char[] chars = strCode.ToCharArray(); 13 //根據(jù)獲取對字符進行編碼所產(chǎn)生的字節(jié)數(shù)來創(chuàng)建一個byte數(shù)組 14 byte[] bytes = new byte[encoder.GetByteCount(chars, 0, chars.Length, true)]; 15 16 //將字符寫入到byte數(shù)組中 17 encoder.GetBytes(chars, 0, chars.Length, bytes, 0, true); 18 19 return bytes; 20 } 21 22 /// <summary> 23 ///獲取字符串解碼之后的字符串 24 /// </summary> 25 /// <param name="codeType">編碼格式</param> 26 /// <param name="byteCode">編碼的字節(jié)數(shù)組</param> 27 /// <returns></returns> 28 private string GetDecodeBeforeText(string codeType, byte[] byteCode) 29 { 30 //根據(jù)編碼類型構造該類型編碼的解碼器的實例 31 Decoder decoder = Encoding.GetEncoding(codeType).GetDecoder(); 32 33 //計算對字節(jié)序列(從指定字節(jié)數(shù)組開始)進行解碼所產(chǎn)生的字符數(shù) 34 char[] chars = new char[decoder.GetCharCount(byteCode, 0, byteCode.Length,true)]; 35 36 //根據(jù)獲取的解碼所產(chǎn)生的字節(jié)數(shù)來創(chuàng)建一個char數(shù)組 37 int charLen = decoder.GetChars(byteCode, 0, byteCode.Length, chars, 0); 38 39 StringBuilder strResult = new StringBuilder(); 40 41 foreach (char c in chars) 42 { 43 strResult = strResult.Append(c.ToString()); 44 } 45 return strResult.ToString(); 46 }
運行程序:
|
|
來自: 空城66 > 《Socket編程 編碼和解碼》