在网络通信中,很多情况下:比如说QQ聊天,通讯双方直接传递的都是字符信息。但是字符信息并不能够直接通过网络传输,这些字符集必须先转换成一个字节序列后才能够在网络中传输,于是这里就产生了编码和解码的概念:
- 将字符序列转换为字节序列的过程称之为:编码
- 将编码的字节序列转换为字符序列的过程称之为:解码
例如:对于Unicode字符来说,编码是指将一组Unicode字符转换为一个字节序列的过程,解码就是讲一个编码字节序列转换为一组Unicode字符。
目录索引:
字符编码基础知识
字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。常见的编码方式主要有一下三种:
1.1 ASCII字符集
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语,而其扩展版本EASCII则可以勉强显示其他西欧语言。它是现今最通用的单字节编码系统(但是有被Unicode追上的迹象),并等同于国际标准ISO/IEC 646。
1.2 非ASCII字符集
由于ASCII字符集是针对英语设计的,当处理汉字等其他非拉丁语系的字符时,这种编码就不能适用了(因为适用128个字符表示英文是完全足够的,但是用了表示中文就远远不够了)。为了解决这个问题,不同的国加和地区制定了自己编码标准。中国一般适用国标码,常用的有GB2312-1980编码和GB183030-2000编码,其中GB183030-2000编码汉字更多,是中国计算机系统必须遵循的基础性标准之一。
1.3 Unicode字符集
由于每个国家、语系都拥有独立的编码方式,同一个二进制数字可以被解释成不同的字符,因此要想打开一个文本文件,就必须知道它的编码方式,否则就可能出现乱码。为了使用国际信息交流更加方便,非营利机构统一码联盟制定和标准化了Unicode字符集。使用16位的编码空间。也就是每个字符占用2个字节。这样理论上一共最多可以表示216(即65536)个字符。基本满足各种语言的使用。实际上当前版本的统一码并未完全使用这16位编码,而是保留了大量空间以作为特殊使用或将来扩展。
1.4 UTF(通用转换格式)的出现
Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的(例如:在C#中字符默认都是Unicode码,即一个英文字符占两个字节,一个汉字也是两个字节,这对于能适应ASCII字符集来表示的字符来说比较显得浪费。),对Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称UTF)。目前流行和UFT格式包括UTF-8、UTF16和UTF-32。
其中,UTF-8编码是互联网上使用最广泛的一种UTF格式,这是一种变长编码,它将基本7位ASCII字符仍用7位编码表示,占用一个字节(首位补0)。而遇到与其他Unicode字符混合的情况,将按一定算法转换,每个字符使用1-3个字节编码,并利用首位为0或1进行识别。这样对以7位ASCII字符为主的西文文档就大大节省了编码长度。UTF-8是与字节顺序无关的,它的字节顺序在所有系统中都是一样的,因此这种编码可以使排序变得很容易。
2.C#中不同编码和Unicode之间的转换
在C#语言中对于不同编码和Unicode之间的转换使用位于System.Text命名空间中的Encoding类。通过这个类我们可以为不同字符集直接进行转换以及各个字符集的相关信息 。
2.1 获取系统所有编码信息
我们通过调用Encoding类的GetEncodings()方法获取包含所有编码的数组,通过数组元素为EncodingInfo类,通过数组内的元素可以获得各种类型编码的信息。例如我们可以通过下面的代码获取主机上所有编码的信息:
1 //获取系统所有编码名称及其描述信息 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类提供了常用的字符集编码可以直接通过调用属性获取:UTF-8,ASCII等属性,也可以通过调用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在不同编码之间进行转换
namespace 编码实例
{
class Program
{
static void Main(string[] args)
{
string str = "M国";
//Unicode编码(.net默认的字符编码)
Encoding uniStr = Encoding.Unicode;
byte[] uniByte = uniStr.GetBytes(str); //获取Unicode编码 (两个字节表示一个字符)
Console.Write("M国的Unicode编码为");
foreach (byte b in uniByte)
{ Console.Write( b+"-"); }
Console.WriteLine();
string str2 = uniStr.GetString(uniByte); //获得编码的字符串 即“M国”
Console.WriteLine("Unicode编码代表的字符是"+str2);
Console.WriteLine();
string GB18030String = "你好!晴天猪";
Encoding gb18030 = Encoding.GetEncoding("GB18030");
byte[] gbByte= gb18030.GetBytes(GB18030String);
Console.Write("你好!晴天猪的GB18030编码为:");
foreach (byte b in gbByte)
{ Console.Write(Convert.ToString (b,16) + "-"); }
Console.WriteLine();
string str22 = gb18030.GetString(gbByte); //获得编码的字符串 即“M国”
Console.WriteLine("GB18030编码代表的字符是:" + str22);
Console.WriteLine();
//ASCII编码()
Encoding ascStr = Encoding.ASCII;
byte[] ascByte = ascStr.GetBytes(str); //获取ASCII编码 (一个字节表示一个字符)
Console.Write("M国的ASCII编码为");
foreach (byte b in ascByte)
{ Console.Write(b + "-"); }
Console.WriteLine();
string str3 = ascStr.GetString(ascByte); //获得编码的字符串 即“M国”,出现乱码(因为一个字节表示不了汉字)
Console.WriteLine("ASCII编码代表的字符是" + str3);
Console.ReadLine();
}
}
}