java 编码 + IO + 网络

java 编码 + IO + 网络

编码

java开发者都遇到过编码问题,各种乱码往往搞得自己焦头烂额。但实际上,只要理清“编码”的概念,应付乱码的问题其实很简单。

“编码”的组成

编码体系由两个方面组成,一个叫:字符集,一个叫编码方式。

什么叫字符集呢?其实就是一个字典。我们知道,计算机存储使用二进制的方式,那么所谓的字符集,就是将我们日常中常用的符号和二进制对应起来,
比如 大写字母A 的二进制表示是:1010 。所以字符集实际上是一个字典,将现实世界的符号映射到计算机的表示,我们在使用电脑的时候,屏幕上显示
的文字、符号等,都是计算机通过将二进制的编码和字符集对照后,将字符取出显示在屏幕上的。

然而,我们可能会发现,既然有了字符集,那么问题不是就解决了吗?还要什么编码方式。其实这和计算机的发展历史有关系。最早计算机出现在英语国家,
导致,最初的字符集是:ASCII码,这个字符集中只包含英语所有的字母和常用符号。并不包含其他语系的字符。所以,要让自己国家的语言可以在计算机上
使用,必须使用包含自己国家语言的字符集。

这个时候,一个伟大的字符集诞生了,Unicode字符集。Unicode字符集涵盖了世界上所有国家的语言符号。这时候,或许我们应该开心了,这下好了,问题
解决了。但是上面的编码方式到底是用来干嘛的?这里我们不得不提一下Unicode字符集的一些更实际的问题,它是怎么表示符号的(如何映射的)?尽管我
不想说这些,因为相对乏味,但是如果不知道这些,就无法理解编码方式的概念了。

首先Unicode按照不同的文字给出了一个连续的区间。比如:0~255共256个符号,可以表示基本的英文字母和字符,(00000000 ~ 11111111)八位,使用一个
字节的即可表示。而中文基本汉字:19968~‭40869‬(‭‭0100111000000000‬ ~ 1001111101000101‬),使用两个字节的即可表示。当然还有阿拉伯文之类的,都有
自己的标识区间。然而Unicode是定长的,即用同样的字节数表示所有的字符(2字节或者4字节)。比如英文字母A,使用 00000000 00001010 即前面的一个
字节全部填充0,第二个字节不足8位的前面几位也填充0。中文类似。

这个时候,科学家发现一个问题,我们是可以表示出所有的字符了,但是英文国家,明明可以使用 一个字节就可以存储的字符比如A(0001010)我们需要在
硬盘中存储成(00000000 00001010),平白无故的多占用了一倍的存储。在网络中传输时同样存在这个问题。

于是乎引出了编码方式。编码方式即实际字符在硬盘中存储的表示方式(或者网络传输时),这时候,我们常见的UTF-8编码方式就出现了。我们以UTF-8来说明。
首先UTF-8是可变长的编码方式,什么是可变长呢?可变长就是,不同语言的字符,所占用的存储长度不同,比如,英文字符占用一个字节表示,中文字符占用三个
字节表示。这个时候,我们发现英文的表示又编程1个字节了,老外很开心。那么既然字符是可变长的,计算机如何知道,下面读取的字节是一个字节表示一个字符,还是
两个、三个、四个字节表示一个字符呢?这时候就要说一下UTF-8编码的规定了。

如果一个字节表示一个字符,那么字节的第一位比如为0,比如 0xxxxxxx 字符A的表示:00001010.
如果两个字节表示一个字符,那么字节的前两位比如为1,并且后面跟一个0作为隔断,第二个字节,以10开头。比如 110xxxxx 10xxxxxx 即,xxxx的部分是实际的编码部分,
依次类推三个字节的表示就是 1110xxxx 10xxxxxx 10xxxxxx。即除了第一个字节中的1表示几个字节表示这个字符外,其余字节都以10开头。

这就是所谓的UTF-8编码方式。

所以,到这里,我们可以看到,所谓的字符集,其实只表示字符的表示。而编码方式决定了,字符在电脑中实际的存储和传输真正的字节表示。

乱码的产生

说到这里,貌似没说,为啥会有乱码,这不得不说又一个常见的字符集,GBK。所谓GBK就是国标码的拼音开头字母。这是中国人自己设计的字符集,所有汉字占两位,并且
编码方式和字符集一样。这时候我们发现,中文在UTF-8中占3个字节,而在GBK编码中只占两位,更加节省存储和带宽。这就是说,如果你的网站只针对中国人,不管老外
能不能看到,就可以使用GBK作为网站的默认编码。是你的网站相应速度更快。

然而,GBK的字符集和Unicode是完全不一样的,汉字 中,在GBK中表示是(‭1101011011010000‬),而Unicode表示是(‭0100111000101101‬)。所以当我们的字符中以GBK
存储在文件中,而我们打开文件时候,使用Unicode的编码方式UTF-8去解析时,就会错误,导致乱码。(这里不讲GBK具体的编码方式了,有兴趣可以自己去了解。)

当然,世界上有各种各样的编码,这就是为什么会导致乱码的原因。

如何避免

开发中要同意编码方式,使用统一的编码方式,是不出错的最好的解决方法。

关于java的部分

首先,我们需要了解一个常识,就是,java虚拟机中表示字符采用Unicode,而非UTF-8,即用Unicode直接表示字符。无论你的java文件是UTF-8也好,GBK也好,最后,读取
到java虚拟机中都是用Unicode表示,并且,每种字符集都提供了和Unicode的映射。这就是为什么,我们可以在java中自由的getBytes("GBK")或者getBytes("UTF-8")进
行随意编码的原因。

posted on 2018-02-09 11:08  大胡子爸爸  阅读(88)  评论(0)    收藏  举报

导航