字符集的编码和解码(ASCII、Unicode、UTF-8和GBK)

ASCII 和 Unicode   

      字符,就是电脑屏幕上能够显示的一个符号,它可以是阿拉伯数字、英文文字、汉语文字、日语文字等等只要收录了的各种各样用于显示的符号。但是,对于计算机而言它们是不认识这种符号的,计算机就能够计算0、1组成的数据。所以,对于这些符号我们要将它进行编码,然后让计算机“认识”它。我们处理这些符号,计算机在底层处理这些编码,我们就能够进行各种编辑任务了。

      对于早期的计算机而言,它是美国人设计出来的,所以设计者只考虑英文的相关字符。对这些字符进行编码,就是我们所熟悉的ASCII,这样的编码占用1byte。但是,随着计算机技术的快速发展,各国人都需要引进信息化,这个时候就要照顾到各国的文字。所以就要设计一种编码方式,它能够对世界上的几乎所有字符进行编码,这就是Unicode,当然这个时候再用1byte显然不够了。Unicode规定世界上常用的字符用2byte进行编码,对于不常用的字符用4byte进行编码。

      首先看一下ASCII和Unicode编码的联系, 

 

字符ASCIIUnicode
A0100000100000000 01000001
X01001110 00101101

      可以看到对于英文字母,只要在前面增加一个字节补充“00000000”就可以了,而对于汉语字符,则是进行重新编码的,对于常用的汉语字符(例如“中”)两个字符就够了。

    我们在进行编辑任务的时候,字符的编码存储于计算机的主存中。如果添加了“A”,主存中就会有2个byte的空间存储“00000000 01000001”,我们要删除“A”,那么这2个byte也就会释放。

UTF-8 和 GBK

      完成编辑任务,我们终究要把我们编辑的文字存储起来或是通过网络发送给他人。当然我们可以就按照Unicode的编码方式将文字永久存储或是传递给别人,但是这里面存在一个问题就是存储效率(传输效率)的问题。对于一份英文文档,本来一个byte就能够存储,这回需要2个byte存储,不要小看这多出来的一倍,因为服务器要存储的并不是我们个人要编辑的一个两个文档,而是全世界所有的信息化数据,多出来的一倍就意味着多出一倍的硬盘。

      为了解决上面这个问题,计算机科学家就设计出来各种各样的存储格式,例如UTF-8、GBK等等。这里我们主要介绍UTF-8和GBK。

      首先说说UTF-8,UTF-8将一个Unicode字符编码成1-6个字符。常用的英文字母被编译成1个byte,汉字通常是3个byte,生僻的字符会编码成4-6个byte。简单梳理一下UTF-8的编码规则:

      1.对于单个字节的字符(例如英文字母“A”),第1位设为0,后面7位对应这个字符的Unicode的码点。所以对于英文中的1-127号字符,对应的就是ASCII的编码。

      2.对于需要N(N > 1)个byte才能够表示的字符(例如汉字“中”),第1个byte的前N位都设为1,第N+1为设为0,剩余的N-1个byte的前两位都设为10,剩下的二进制位置就使用这个字符的Unicode来填充。

 

字符ASCIIUTF-8
A00000000 0100000101000001
01001110 0010110111100100 10111000 10101101

      那么对于内存中的一个字符,当我们要存入硬盘或是传输的时候,就通过上面的方式进行编码。当我们从硬盘中读文件或是从网络中接收到文件的时候,同样按照上面的规则进行解码出来Unicode到内存中,我们就能够看到“A”和“中”了。这里面还有一个小惊喜,对于历史很久远的用ASCII进行编码的字符所存储的文件,同样可以用今天设计出来的UTF-8的编码方式进行解码,然后进行文字的阅读。

      说到了存储效率,会发现如果一个文本中英文字符很多还好,如果通篇都是汉字会发现存储效率反而下降。这就需要采用更节约的编码方式---GBK。GBK兼容英文字符,同时一个汉字占用2个byte。GBK和Unicode同时也有一套转换规则。

再聊字符集的编码与解码

      当我们打开一个文件有时候会发现都是乱码,这里面的原因就是因为存储的文件编码方式和解码方式不同造成的。 我们以UTF-8的编码方式存储一个文件或是通过网络传递一段信息,那么除了用UTF-8解码意外,使用其他的解码方式都会出现乱码。

      其实对于存储或是网络传输的编码来说,这是一个比较底层的操作。

      这个操作对应的Java代码

     

 byte[] codedByteArr = str.getBytes("charset"); //编码

      通过上面这段代码我们能够将一段字符集合(字符串)转化为你想转化的字符集的编码,这也就是从Unicode到各种编码方式的编码过程。 

    String str = new String(byte[] codedByteArr, Charset charset);//解码

      通过上面这段代码我们能够将一段编码数组解码成字符集合(字符串),这也就是从各种编码方式到Unicode的解码过程。

      当我们如果想将一段文本从一种编码方式转到另一种编码方式,那么正确的操作方式一定是   A编码方式->Unicode->B编码方式,一定不存在  A编码方式->B编码方式 的方法。

 

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值