Java中的字符集编码

一、Unicode与UCS

     ASCII是美国标准信息交换码的缩写,ASCII码规定用7位二进制数字表示英文字符。ASCII被定为国际标准之后的代号为ISO-646。一个字节可以表示256个数字中,ASCII码只使用了0~127这128个码位,剩下的128个码位是用来做扩展,用来表示一些其他语言所独有的字符。因此对剩下的128个码位的不同扩展,就形成了一些列ISO-8859-*的标准。

     整个Unicode项目是由多家计算机软件公司,还有其他公司共同发起的,从上世纪八十年代就已经开始。由于汉字、日文来说,256个码位远远不够用,故Unicode希望采用码位多到可以包含世界上所有语言的字符,但是仅靠原先的设计无法实现,Unicode对所有字符都采用16位编码,是一个16位的编码字符集,即用一个大小不超过2的16位次方的整数数字给每个符号编码。但是后来发现,16位编码仅有65536个码位,远远不能容纳世界上所有的字符。当意识到这个问题的时候,Unicode的规范已经大部分都制定完毕了,也有相当程度的普及,所以不能推到重来。

     在1984年,国际标准化组织ISO也着手着制定解决方案,这个方案称为Universal Character Set(UCS统一字符集),正式的编号是ISO-10646。UCS是一个31位的编码字符集,但是后来发现2的31次方个码位实在是太多了。

     在1991年,Unicode联盟与ISO的工作组终于开始讨论Unicode与UCS的合并问题。最终两者统一了抽象字符集(即任何一个在Unicode中存在的字符,在UCS中也存在),且靠最前的65536个字符也统一了字符的编码。对于码空间,两者同意以一百一十万为限(大概的数),Unicode将码空间扩展到了一百一十万,而UCS将永久性的不适用一百一十万以后的码位。因此再讲Unicode只包含65536个字符是不对的。

二、编码字符集与字符集编码的区别

    无论UCS还是Unicode,两者指的都是编码字符集,而不是字符集编码。一个抽象字符集其实就是指字符的集合。之所以说“抽象”二字,是因为这里所提及的字符是不具任何具体形式的字符。例如“汉”这个字符,在文章中看到这个“汉”字,这其实是这个字符的一种具体表现形式,是它的图像表现形式,而且它是用中文书写而成,当人们读“汉”这个字的时候,他们使用的是另一个具体表现形式---声音。但是无论如何,这两个表现形式都是指这个“汉”字,同一个字符的表现形式可能有无数种(点阵法、矢量法、音频等),把每一种的表现形式下的同一个字符都纳入到字符集中,会使得集合过于庞大。因此抽象字符集中的字符,都是指唯一存在的抽象字符,而忽略了它的具体表现形式。在给定一个抽象字符集合中的每个字符都分配了一个整数编号之后,这个字符集就有了顺序,就成为了编码字符集。同时,这个编号,可以唯一确定到底指的是哪一个字符。对于同一个字符,不同的字符集编码系统所指定的整数编号也不尽相同。例如“儿”这个字,在Unicode中,它的编号是0x513F,意思是它是Unicode这个编码字符集中的第0X513F个字符。而在另一种编码字符集中,这个字是0xA449。还有另一种情况是,许多字符在不通电额编码字符集中被分配了相同的整数编号,例如英文字母'A',在ASCII及Unicode中,均是第0x41个字符。Unicode字符集,指的是这种被分配了整数编号的字符集合,但是编码字符集中字符被分配的整数编号,不一定就是该字符在计算机中存储时所使用的值,计算机中存储的字符到底使用什么二进制整数值来表示,由字符集编码决定。

      字符集编码决定了如何将一个字符的整数编号对应到一个二进制的整数值。英文字符几乎所有的字符集编码中,英文字母的整数编号与其在计算机内部存储的二进制形式都一致。但是有的编码方式中,例如适用于Unicode字符集的UTF-8编码形式,就将很大一部分字符的整数编号作了变换后存储到计算机中。例如“汉”的Unicode值为0x6C49,

但其编码格式为UTF-8格式后的值为0xE6B189(3个字节)。

    UTF-8编码,将字符编号变换成3个字节存储

    UTF-16编码,是将前65536个字符编号不做变换,直接将整数编号存储到计算机中。而后面的值需要做变换。UTF-16提供了surrogate pair机制(基本思想是用2个16位的编码表示一个字符,只对超过65536的字符这么做),使得Unicode中码位大于65536的那些字符得以表示。

    UTF-32编码,对所有的Unicode字符均不做变换,直接使用编号存储。没有得到普及。

三、GB2312、GBK

    GB2312最初指的是一个编码字符集。它有自己的编码方案,但这个方案直接使用一个字符在GB2312中的编号作为存储值,所以我们说的GB2312既指编码字符集也指编码方案。

    GBK是GB2312的后续标准,添加了更多的汉字和特殊符号,(由于GB2312不够用),GBK也是指编码字符集合编码方案。GBK如今还是中文Windows操作系统的系统默认编码方案。

    中文网页的编码

    1.在html页面中meta标签的部分,常常可以见到charset=GB2312,这个charset其实是用来指定页面使用的是什么字符集编码,而不是什么字符集。

    2.在xml页面中,encoding=GB2312,这个GB2312实际上并不是真的GB2312。浏览器会选择GBK的编码进行解析。

  四、网页文件的编码

       一个网页要想在浏览器中能够正确显示,需要在三个地方保持编码的一致:网页文件、网页编码声明和浏览器编码设置。

       网页文件本身的编码,即网页文件被创建的时候使用什么编码来保存,而进一步取决于该人员使用的操作系统。

       一个在创建xml文件时,常见的误解就是以为只要在页面的encoding部分声明了UTF-8,则文件就会被保存为UTF-8格式。实际上XML文件中encoding部分与html文件中的charset中一样,只是告诉“别人”这个文件使用了什么编码,唯独操作系统不会搭理,它仍然会按自己默认的编码方式保存文件。

      网页文件的编码与声明的编码要保持一致。

五、Java代码中的字符编码

      在Java中,字符只以一种形式存在,那就是Unicode(我们没有选择特定的编码,直接使用它们再字符集中的编号,这是统一的唯一方法)。JVM的这种统一使用Unicode表示,当这个字符被从JVM内部移到外部(即保存为文件系统中的一个文件的内容时),就进行了编码转换,使用了具体的编码方案。

     因此,所有的编码转换就只发生在边界的地方,JVM和OS的交界处,也就是各种输入输出流起作用的地方。

     IO基本上可以分为两大阵营,面向字符的Reader和Writer,以及面向字节的输入输出流。

     面向字节,那么这类工作要保证系统中的文件二进制内容和读入JVM内部的二进制内容保持一致。文件是怎么存的就怎么取,与文件保存的编码一致。

    面向字符的IO是指希望系统中的文件的字符和读入内存的“字符”要一致。

    实际上,Reader和Writer类隐式的为我们做了编码转换,在输出时,将内存中的Unicode字符使用系统默认的编码方式进行了编码。而在输入时,将文件系统中已经编码过的字符使用默认编码方案进行了还原。默认就是说Reader和Writer只能以操作系统默认编码方式进行转换。所谓编码转换就是一个字符与字节之间的转换。InputStreamReader和OutputStreamWriter类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值