一、有关编码的基础知识1.位bit最小的单元字节byte机器语言的单位1byte8bits1KB1024byte1MB1024KB1GB1024MB2.二进制binary八进制octal十进制decimal十六进制hex3.字符是各种文字和符号的总称包括各个国家的文字标点符号图形符号数字等。字符集字符集是多个符号的集合每个字符集包含的字符个数不同。字符编码字符集只是规定了有哪些字符而最终决定采用哪些字符每一个字符用多少字节表示等问题则是由编码来决定的。计算机要准确的处理各种字符集文字需要进行字符编码以便计算机能够识别和存储各种文字。二、常见字符编码的介绍首先来看一下常用的编码有哪些截图自Notepad。其中ANSI在中国大陆即为GBK以前是GB2312最常用的是GBK和UTF8无BOM编码格式。后面三个都是有BOM头的文本格式UCS-2即为人们常说的Unicode编码又分为大端、小端。所谓BOM头Byte Order Mark就是文本文件中开始的几个并不表示任何字符的字节用二进制编辑器如bz.exe就能看到了。UTF8的BOM头为0xEF 0xBB 0xBFUnicode大端模式为0xFE 0xFFUnicode小端模式为0xFF 0xFE说明需要添加插件HEX-EditorASCII码计算机一开始发明的时候是用来解决数字计算的问题后来人们发现计算机还可以做更多的事例如文本处理。但由于计算机只识“数”因此人们必须告诉计算机哪个数字来代表哪个特定字符例如65代表字母‘A’66代表字母‘B’以此类推。但是计算机之间字符-数字的对应关系必须得一致否则就会造成同一段数字在不同计算机上显示出来的字符不一样。因此美国国家标准协会ANSI制定了一个标准规定了常用字符的集合以及每个字符对应的编号这就是ASCII字符集Character Set也称ASCII码。那时候的字符编解码系统非常简单就是简单的查表过程。例如将字符序列编码为二进制流写入存储设备只需要在ASCII字符集中依次找到字符对应的字节然后直接将该字节写入存储设备即可。解码二进制流的过程也是类似。其中031及127(共33个)是控制字符或通信专用字符其余为可显示字符如控制符LF换行、CR回车、FF换页、DEL删除、BS退格)32126(共95个)是字符(32是空格其中4857为0到9十个阿拉伯数字。6590为26个大写英文字母97122号为26个小写英文字母其余为一些标点符号、运算符号等。后128个称为扩展ASCII码。许多基于x86的系统都支持使用扩展或“高”ASCII。扩展ASCII码允许将每个字符的第8位用于确定附加的128个特殊符号字符、外来语字母和图形符号。OEM字符集的衍生当计算机开始发展起来的时候人们逐渐发现ASCII字符集里那可怜的128个字符已经不能再满足他们的需求了。人们就在想一个字节能够表示的数字编号有256个而ASCII字符只用到了0x00~0x7F也就是占用了前128个后面128个数字不用白不用因此很多人打起了后面这128个数字的主意。可是问题在于很多人同时有这样的想法但是大家对于0x80-0xFF这后面的128个数字分别对应什么样的字符却有各自的想法。这就导致了当时销往世界各地的机器上出现了大量各式各样的OEM字符集。大家对于0x00~0x7F这个范围的解释基本是相同的而对于后半部分0x80~0xFF的解释却不一定相同。甚至有时候同样的字符在不同OEM字符集中对应的字节也是不同的。不同的OEM字符集导致人们无法跨机器交流各种文档。例如职员甲发了一封简历résumés给职员乙结果职员乙看到的却是r?sum?s因为é字符在职员甲机器上的OEM字符集中对应的字节是0x82而在职员乙的机器上由于使用的OEM字符集不同对0x82字节解码后得到的字符却是?。多字节字符集MBCS和中文字符集上面我们提到的字符集都是基于单字节编码也就是说一个字节翻译成一个字符。这对于拉丁语系国家来说可能没有什么问题因为他们通过扩展第8个比特就可以得到256个字符了足够用了。但是对于亚洲国家来说256个字符是远远不够用的。因此这些国家的人为了用上电脑又要保持和ASCII字符集的兼容就发明了多字节编码方式相应的字符集就称为多字节字符集Muilti-Bytes Charecter Set。例如中国使用的就是双字节字符集编码。例如目前最常用的中文字符集GB2312涵盖了所有简体字符以及一部分其他字符GBKK代表扩展的意思则在GB2312的基础上加入了对繁体字符等其他非简体字符。这两个字符集的字符都是使用1-2个字节来表示。Windows系统采用936代码页来实现对GBK字符集的编解码。在解析字节流的时候如果遇到字节的最高位是0的话那么就使用936代码页中的第1张码表进行解码这就和单字节字符集的编解码方式一致了。如果遇到字节的最高位是1的话那么就表示需要两个字节值才能对应一个字符。假如你使用GB2312写了这么一句话我叫ABC它的二进制编码是这样的11001110 1101001010111101 11010000010000010100000201000003全角全角是一种电脑字符且每个全角字符占用两个标准字符或半角字符位置。通常的英文字母、数字键、符号键都是半角的半角的显示内码都是一个字节。为 了排列整齐英文和其它拉丁文的字符和标点也提供了全角格式。在中文输入法中切换全角和半角格式的快捷键为SHIFT空格。ANSI标准、国家标准、ISO标准不同ASCII衍生字符集的出现让文档交流变得非常困难因此各种组织都陆续进行了标准化流程。例如美国ANSI组织制定了ANSI标准字符编码注意我们现在通常说到ANSI编码通常指的是平台的默认编码例如英文操作系统中是ISO-8859-1中文系统是GBKISO组织制定的各种ISO标准字符编码还有各国也会制定一些国家标准字符集例如中国的GBKGB2312和GB18030。操作系统在发布的时候通常会往机器里预装这些标准的字符集还有平台专用的字符集这样只要你的文档是使用标准字符集编写的通用性就比较高了。例如你用GB2312字符集编写的文档在中国大陆内的任何机器上都能正确显示。同时我们也可以在一台机器上阅读多个国家不同语言的文档了前提是本机必须安装该文档使用的字符集。Unicode的出现虽然通过使用不同字符集我们可以在一台机器上查阅不同语言的文档但是我们仍然无法解决一个问题如果一份文档中含有不同国家的不同语言的字符那么无法在一份文档中显示所有字符。为了解决这个问题我们需要一个全人类达成共识的巨大的字符集这就是Unicode字符集。Unicode字符集涵盖了目前人类使用的所有字符并为每个字符进行统一编号分配唯一的字符码Code Point。Unicode字符集将所有字符按照使用上的频繁度划分为17个层面Plane每个层面上有21665536个字符码空间。其中第0个层面BMP基本涵盖了当今世界用到的所有字符。其他的层面要么是用来表示一些远古时期的文字要么是留作扩展。我们平常用到的Unicode字符一般都是位于BMP层面上的。目前Unicode字符集中尚有大量字符空间未使用。编码系统的变化在Unicode出现之前所有的字符集都是和具体编码方案绑定在一起的即字符集≈编码方式都是直接将字符和最终字节流绑定死了例如ASCII编码系统规定使用7比特来编码ASCII字符集GB2312以及GBK字符集限定了使用最多2个字节来编码所有字符并且规定了字节序。这样的编码系统通常用简单的查表也就是通过代码页就可以直接将字符映射为存储设备上的字节流了。例如下面这个例子Unicode同样也不完美这里就有三个问题一个是我们已经知道英文字母只用一个字节表示就够了第二个问题是如何才能区别Unicode和ASCII计算机怎么知道两个字节表示一个符号而不是分别表示两个符号呢第三个如果和GBK等双字节编码方式一样用最高位是1或0表示两个字节和一个字节就少了很多值无法用于表示字符不够表示所有字符。Unicode在很长一段时间内无法推广直到互联网的出现为解决Unicode如何在网络上传输的问题于是面向传输的众多UTFUCS Transfer Format标准出现了顾名思义UTF-8就是每次8个位传输数据而UTF-16就是每次16个位。UTF-8就是在互联网上使用最广的一种Unicode的实现方式这是为传输而设计的编码并使编码无国界这样就可以显示全世界上所有文化的字符了。UTF-8最大的一个特点就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号。从unicode到uft-8并不是直接的对应而是要过一些算法和规则来转换即Uncidoe字符集≠UTF-8编码方式。编码936代码页实际上说的是同个东西。但是对于Unicode则不同Unicode字符集只是定义了字符的集合和唯一编号Unicode编码则是对UTF-8、UCS-2/UTF-16等具体编码方案的统称而已并不是具体的编码方案。所以当需要用到字符编码的时候你可以写gb2312codepage936utf-8utf-16但请不要写Unicode。造成乱码的原因就是因为使用了错误的字符编码去解码字节流因此当我们在思考任何跟文本显示有关的问题时请时刻保持清醒当前使用的字符编码是什么。只有这样我们才能正确分析和处理乱码问题。常见CharSet有GBK、GB2312、US-ASCII、ISO-8859-1、UTF-8、UTF-16BE、UTF-16LE、UTF-16