在网络通信中,很多情况下:比如说QQ聊天,通讯双方直接传递的都是字符信息。但是字符信息并不能够直接通过网络传输,这些字符集必须先转换成一个字节序列后才能够在网络中传输,于是这里就产生了编码和解码的概念:

  • 字符序列转换为字节序列的过程称之为:编码
  • 将编码的字节序列转换为字符序列的过程称之为:解码

例如:对于Unicode字符来说,编码是指将一组Unicode字符转换为一个字节序列的过程,解码就是讲一个编码字节序列转换为一组Unicode字符。

目录索引:
  1.字符编码基础知识
      1.1 ASCII字符集
      1.2 非ASCII字符集
      1.3 Unicode字符集
      1.4 UTF(通用转换格式)的出现
  2.C#中不同编码和Unicode之间的转换
      2.1 获取系统所有编码
      2.2 获取指定编码信息
      2.3 不同编码间的转换
  3.C#编码和解码

字符编码基础知识

字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。常见的编码方式主要有一下三种:

1.1 ASCII字符集

  ASCIIAmerican 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类的GetEncoding()方法获取包含所有编码的数组,数组元素为EncodingInfo类,通过数组元素我们可以获得各种类型编码的信息。例如我们可以通过下面的代码获取主机上所有编码的信息:

//获取系统所有编码名称及其描述信息
EncodingInfo[] allEncoding = Encoding.GetEncodings();
foreach (EncodingInfo encoding in allEncoding)
{
Console.WriteLine("编码标识符:{0,-10}编码名称:{1,-12}编码说明:{2}", encoding.CodePage, encoding.Name, encoding.DisplayName);
}
Console.ReadLine();

运行如下:

2.2 获取指定的编码信息

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);

运行如下:

2.3在不同编码之间进行转换

我们可以可以通过利用 Encoding.Convert(+2重载)直接将字节数组从一种编码转换为另一种编码。下面我们同样通过一个示例代码来学习如何对不同编码的字节序列进行转换。下面的示例程序,为了清楚的演示如何使用,可能代码比较冗余(代码中包含解码和编码部分,在随后会给出相应示例),实际的应用中我们可以根据自己的情况进行适当的对方法抽象,重构,提升程序的可读性和效率。代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ConsoleApplication1
{
class Program
{
public static void Main()
{
//不同编码之间的转换
string GB18030String = "你好!晴天猪";
Console.WriteLine("需要转换的字符串:{0}",GB18030String); #region 对字符进行GB18030格式编码 //获取编码器
Encoding gb18030Encoding = Encoding.GetEncoding("GB18030");
//将字符串转换为char类型数组
char[] chars = GB18030String.ToCharArray();
//获取编码为字节序列后的字节数组长度
int buffLength = gb18030Encoding.GetByteCount(chars, , chars.Length);
//根据获取的字节长度声明数组,存储编码后的字节
byte[] gb18030Buffer = new byte[buffLength];
//获取GB18030编码的字节序列
gb18030Buffer = gb18030Encoding.GetBytes(chars, , 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, , unicodeBuffer.Length, true);
//根据获取解码后的长度创建char数组
char[] utfChart = new char[utfChartsLength];
//将UTF-8编码的字节序列转换为字符数组
utf8Decoder.GetChars(unicodeBuffer, , unicodeBuffer.Length, utfChart, );
StringBuilder strBuilder = new StringBuilder();
foreach (char ca in utfChart)
{
strBuilder.Append(ca);
}
Console.WriteLine("UTF-8的字符序列解码:{0}", strBuilder.ToString());
#endregion Console.ReadLine();
}
}
}

运行程序:

3.C#编码和解码

在C#中为我们提供了Encoder和Decoder类,分别对字符进行编码和对字节序列进行解码的两个类。通过使用它们,我们可以很方便进行对字符和字节序列进行编码和解码操作。由于它们的构造函数都是protected级别的,需要使用 Encoding 实现的GetEncoding方法才能获取到它们的实例对象。下面我们通过一个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, , chars.Length, true)]; //将字符写入到byte数组中
encoder.GetBytes(chars, , chars.Length, bytes, , 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, , byteCode.Length,true)]; //根据获取的解码所产生的字节数来创建一个char数组
int charLen = decoder.GetChars(byteCode, , byteCode.Length, chars, ); StringBuilder strResult = new StringBuilder(); foreach (char c in chars)
{
strResult = strResult.Append(c.ToString());
}
return strResult.ToString();
}

运行程序:

猛点击下载:源代码

C# Socket编程(3)编码和解码的更多相关文章

  1. 【转】C# Socket编程(3)编码和解码

    [转自:https://www.cnblogs.com/IPrograming/archive/2012/10/13/CSharp_Socket_3.html] 在网络通信中,很多情况下:比如说QQ聊 ...

  2. Python学习笔记八:文件操作(续),文件编码与解码,函数,递归,函数式编程介绍,高阶函数

    文件操作(续) 获得文件句柄位置,f.tell(),从0开始,按字符数计数 f.read(5),读取5个字符 返回文件句柄到某位置,f.seek(0) 文件在编辑过程中改变编码,f.detech() ...

  3. Socket编程之聊天程序 - 模拟Fins/ModBus协议通信过程

    设备控制软件编程涉及到的基本通信方式主要有TCP/IP与串口,用到的数据通信协议有Fins与ModBus. 更高级别的通信如.net中的Remoting与WCF在进行C/S架构软件开发时会采用. 本篇 ...

  4. Python 基础之socket编程(二)

    Python 基础之socket编程(二) 昨天只是对socket编程做了简单的介绍,只是把socket通信的框架搭建起来,要对其中的功能进行进一步的扩充,就来看看今天的料哈! 一.基于tcp的套接字 ...

  5. 十三python基础之socket编程

      阅读目录 一 客户端/服务器架构 二 osi七层 三 socket层 四 socket是什么 五 套接字发展史及分类 六 套接字工作流程 七 基于TCP的套接字 八 基于UDP的套接字 九 粘包现 ...

  6. python学习------socket编程

    一 客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网中处处是C/S架构 如黄色网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务端为你提供视频 ...

  7. python基础之socket编程

    一 客户端/服务器架构 二 osi七层 三 socket层 四 socket是什么 五 套接字发展史及分类 六 套接字工作流程 七 基于TCP的套接字 八 基于UDP的套接字 九 粘包现象 十 什么是 ...

  8. 网络编程——socket编程

    一.客户端/服务端架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网企业处处是C/S架构 C/S架构与socket的关系:学习socket就是为了完成C/S架构的开发 二.OSI七层 一个 ...

  9. Day10 Python网络编程 Socket编程

    一.客户端/服务器架构 1.C/S架构,包括: 1.硬件C/S架构(打印机) 2.软件C/S架构(web服务)[QQ,SSH,MySQL,FTP] 2.C/S架构与socket的关系: 我们学习soc ...

随机推荐

  1. 刚体Collider包围测试

    测试结果为会自动排出修正坐标(之前位于中心): 2016/2/29补充: 如果外面大的Cube相对小的Cube质量很高,会弹出且不出现移动(已锁住弹出物旋转,如果不锁会飞出去): 如果没有足够的空间排 ...

  2. 《python核心编程》读书笔记--第16章 网络编程

    在进行网络编程之前,先对网络以及互联网协议做一个了解. 推荐阮一峰的博客:(感谢) http://www.ruanyifeng.com/blog/2012/05/internet_protocol_s ...

  3. Java根据条件删除Map中元素

    今天在写程序过程中,需要根据判断条件删除一个Map中的相应数据,我自然而然想到可以通过调用Map中的remove(Object key)函数进行删除:代码如下: public Map<Doubl ...

  4. Mysql-学习笔记(==》常用函数 八)

    -- 常用函数 字符编码uft8汉字为3个字节 gbk汉字两个字节 gbk占用空间小速度快 utf8兼容性好 -- length 返回字符的字节数SELECT LENGTH('asd王');-- ch ...

  5. 自学QT笔记

    前言: Qt 是一个跨平台的 C++图形用户界面库,由挪威 TrollTech 公司于1995年底出品. Trolltech 公司在 1994 年成立,但是在 1992 年,成立 Trolltech ...

  6. 11个让你吃惊的 Linux 终端命令

    原文:http://linux.about.com/od/commands/tp/11-Linux-Terminal-Commands-That-Will-Rock-Your-World.htm 作者 ...

  7. HTML(Open Method)翻译自MSDN

    Open Method Opens a new window and loads the document specified by a given URL. Navigates the app wi ...

  8. oracle dual 表

    dual是一个虚拟表,用来构成select的语法规则,oracle保证dual里面永远只有一条记录.我们可以用它来做很多事情,如下: 1.查看当前用户,可以在 SQL Plus中执行下面语句 sele ...

  9. 【leetcode❤python】118. Pascal's Triangle

    #-*- coding: UTF-8 -*-#杨辉三角class Solution(object):    def generate(self, numRows):        "&quo ...

  10. BZOJ 1006 神奇的国度(弦图的染色数)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1006 题意:给定一个弦图,求最小染色数.就是用最小数目的颜色进行染色使得任意两个相邻的节 ...