【转自: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(); }
运行程序: