java中⼏种常见字符集与乱码介绍1. ASCII和Ansi编码
字符内码(charcter code)指的是⽤来代表字符的内码
.读者在输⼊和存储⽂档时都要使⽤内码,内码分为
单字节内码 -- Single-Byte character sets
(SBCS),可以⽀持256个字符编码.
双字节内码 -- Double-Byte character sets)
(DBCS),可以⽀持65000个字符编码.
前者即为ASCII编码,后者对应ANSI.
⾄于简体中⽂编码GB2312,实际上它是ANSI的⼀个代
码页936
2.Unicode符号集
正如上⼀节所说,世界上存在着多种编码⽅式,同⼀个⼆
进制数字可以被解释成不同的符号。因此,要想打开⼀个
⽂本⽂件,就必须知道它的编码⽅式,否则⽤错误的编码
⽅式解读,就会出现乱码。为什么电⼦邮件常常出现乱码
?就是因为发信⼈和收信⼈使⽤的编码⽅式不⼀样。⽽
Unicode就是这样⼀种编码:它包含了世界上所有的符号,
并且每⼀个符号都是独⼀⽆⼆的。⽐如,U+0639表⽰阿拉
伯字母Ain,U+0041表⽰英语的⼤写字母A,U+4E25表⽰汉
字“严”。具体的符号对应表,可以查询,或
Unicode是⼀个符号集(世界上所有符号的符号集),⽽不是⼀种新的编码⽅式。
但是正因为Unicode包含了所有的字符,⽽有些国家的字符
⽤⼀个字节便可以表⽰,⽽有些国家的字符要⽤多个字节
才能表⽰出来。即产⽣了两个问题:第⼀,如果有两个字
节的数据,那计算机怎么知道这两个字节是表⽰⼀个汉字
呢?还是表⽰两个英⽂字母呢?第⼆,因为不同字符需要
的存储长度不⼀样,那么如果Unicode规定⽤2个字节存储
字符,那么英⽂字符存储时前⾯1个字节都是0,这就⼤⼤
浪费了存储空间。
上⾯两个问题造成的结果是:1)出现了unicode的多种存
储⽅式,也就是说有许多种不同的⼆进制格式,可以⽤来
表⽰unicode。2)unicode在很长⼀段时间内⽆法推⼴,直
到互联⽹的出现。
3.UTF-16
说到 UTF 必须要提到 Unicode(Universal Code 统⼀码
),ISO 试图想创建⼀个全新的超语⾔字典,世界上所有
的语⾔都可以通过这本字典来相互翻译。可想⽽知这个字
典是多么的复杂,关于 Unicode 的详细规范可以参考相应
⽂档。Unicode 是 Java 和 XML 的基础,下⾯详细介绍
UTF-16 具体定义了 Unicode 字符在计算机中存取⽅法。UTF-16 ⽤两个字节来表⽰ Unicode 转化格式,这个是定长的表⽰⽅法,不论什么字符都可以⽤两个字节表⽰,两
个字节是 16 个 bit,所以叫 UTF-16。UTF-16 表⽰字符
⾮常⽅便,每两个字节表⽰⼀个字符,这个在字符串操作时就⼤⼤简化了操作,这也是 Java 以 UTF-16 作为内存
的字符存储格式的⼀个很重要的原因。
4.UTF-8
UTF-16 统⼀采⽤两个字节表⽰⼀个字符,虽然在表⽰上⾮常简单⽅便,但是也有其缺点,有很⼤⼀部分字符⽤⼀个字节就可以表⽰的现在要两个字节表⽰,存储空间放⼤了⼀倍,在现在的⽹络带宽还⾮常有限的今天,这样会增⼤⽹络传输的流量,⽽且也没必要。⽽ UTF-8 采⽤了⼀种变长技术,每个编码区域有不同的字码长度。不同类型的字
符可以是由 1~4 个字节组成。
UTF-8 有以下编码规则:
如果⼀个字节,最⾼位(第 8 位)为 0,表⽰这是⼀个ASCII 字符(00 - 7F)。可见,所有 ASCII 编码已经是
UTF-8 了。
如果⼀个字节,以 11 开头,连续的 1 的个数暗⽰这个字符的字节数,例如:110xxxxx 代表它是双字节 UTF-8 字
5.GBK/GB2312/GB18030
GBK和GB2312都是针对简体字的编码,只是GB2312只⽀持六千多个汉字的编码,⽽GBK⽀持1万多个汉字编码。⽽
GB18030是⽤于繁体字的编码。汉字存储时都使⽤两个字节
来储存。
总的来说:
ASCII编码:⽤来表⽰英⽂,它使⽤1个字节表⽰,其中第
中文字符unicode查询⼀位规定为0,其他7位存储数据,⼀共可以表⽰128个字符
。
拓展ASCII编码:⽤于表⽰更多的欧洲⽂字,⽤8个位存储
数据,⼀共可以表⽰256个字符
GBK/GB2312/GB18030:表⽰汉字,⽤两个字节表⽰。
GBK/GB2312表⽰简体中⽂,GB18030表⽰繁体中⽂。Unicode编码:包含世界上所有的字符,是⼀个字符集。UTF-8:是Unicode字符的实现⽅式之⼀,它使⽤1-4个字节
表⽰⼀个符号,根据不同的符号⽽变化字节长度。
UTF-16:
UTF-8:是Unicode字符的实现⽅式之⼀,它使⽤2个字节表
⽰⼀个符号
乱码问题的产⽣最根本的原因就是使⽤错误的字符集解码字节流或者将给定的字符串⽤错误的字符集编码成错误字节流造成的,例如”中⽂”两个汉字,如果⽤ISO8859-1字符集将其编码为字节流,因为这个字符集不⽀持中⽂,所以就会出错,输出结果为3f3f,其意义就是??。再例如”中⽂”⼆字的GBK的字节流为d6 d0 ce c4,可是我们要是⽤不兼容的字符集去解码,例如⽤ISO8859-1或者UTF-8,这随后产⽣的字符串就是乱码,或者是其他的某个字符。
解决java编程中出现乱码的⽅法:
从开发Java程序到运⾏Java程序的过程中都存在着编码问题,所以要想避免乱码产⽣,就必须了解在
其中任何时候的编码处理的情况。1、源代码:在编写java源代码的时候,我们必须把编写的⽂本保存在⽂件中,这个时候不管⽤什么编辑器,都存在⼀个问题,就是以什么
样的字符集将这些源代码(包含汉字)保存到⽂件中,⼤部分编辑器都会通过系统的环境变量得到系统的当前默认字符集,编辑器就会使⽤这个字符集将我们编写的源代码保存到⽂件中。⼀般我们的中⽂Windows系统的默认字符集是GB18030,AIX英⽂环境的默认字符集是ISO8859-1,AIX中⽂环境的默认字符集是IBM-eucCN。
2、编译:在编译.java⽂件的时候如果使⽤默认处理,则javac会使⽤系统当前的默认字符集去读取源⽂件,将源⽂件的内容转换为UTF-8编码,然后在进⾏编译,这时我们也可以通过-encoding参数指定⼀个字符集,让javac使⽤我们指定的字符集去读取源代码然后在转换为UTF-8,然后编译。编译以后产⽣的class⽂件内部所有的中⽂字符都是⽤UTF-8的字符集进⾏编码的,这就是Java程序能处理任何国家⽂字的原因。
3、运⾏时:Java程序在运⾏时,需要使⽤程序内部定义的中⽂字符串,也可能会使⽤从外部读取的中⽂字符串,这些经过处理,可能都会输出到程序外部,在这些过程中都涉及到编码的转换,程序内部定义的字符串都是⽤UTF-8存储的。⽽从外部读取和输出到程序外部的输出⼜使⽤什么字符集进⾏处理呢?在我们没有在程序中特别指定的情况下,JVM会根据系统属性确定使⽤哪个字符集,这个系统
属性的名称为ding,我们可以在启动java程序的时候通过-D参数设定这个值,如果没有设定,JVM会根据系统环境变量确定这个系统属性,⼀般我们的中⽂Windows系统的默认字符集是GB18030,AIX英⽂环境的默认字符集是ISO8859-1,AIX中⽂环境的默认字符集是IBM-eucCN。这样JVM在处理输⼊数据的时候就会把字节流根据这个参数进⾏解码,然后转成UTF-8格式,在Java程序内部处理,然后再根据这个参数把处理后的数据编码,输出到程序外部。这就是Java程序运⾏时字符集的使⽤情况。
现在有⼀个问题,我们平时都是Windows的中⽂环境下做开发,然后拿到AIX系统上去运⾏,AIX系统的默认语⾔环境是英⽂环境,这样就会出现乱码,分析过程如下:源⽂件编码格式为GB18030,默认编译,也采⽤GB18030读取源⽂件,正常转换为UTF-8,⽣成class⽂件,运⾏时没有进⾏特殊设置,语⾔环境为英⽂环境,默认编码为ISO8859-1,这样在输出中⽂的时候会把正常的UTF-8表⽰的汉字⽤ISO8859-1的字符集去编码⽣成字节流,因为ISO8859-1不⽀持汉字,结果输出的都是’?’。可是这个时候却发现,由外界输⼊给java程序的中⽂字符,却能正常输出,这⼜是为什么,其实这个也是运⾏时的默认字符集ISO8859-1造成的,Java程序运⾏时,在读取外部进⼊的字节流的时候,如果使⽤默认的读取⽅式,也是使⽤ISO8859-1的字符集进⾏解码处理,这样中间的处理过程中,中⽂都已经不是原来的中⽂了,也就是说我们这个时候处理根本不是我们认为的中⽂,⽽是⼀对乱码,虽然是乱码,但是其中的信息却没有丢失,在处理完后,在经过⼀次ISO8859-1的编码,⼜还原为正常的GB18
030的编码输出,所有没有出现乱码。我们以前的解决⽅法是,在编译原⽂件的时候指定参数-encoding ISO8859-1,让编译器⽤ISO8859-1的字符集去解码源⽂件编译,然后运⾏程序,这时再输出程序的内部中⽂字符串也不是乱码了。看起来⼀切都解决了,可是却没有从根本上解决问题,class⽂件变得⽐平常⼤很多,程序中⽤到中⽂越多,class⽂件变⼤的越快。⽽且其中的中⽂信息也变味了。
另⼀个问题,如果我们正常编译程序,在AIX系统上线设定为中⽂环境,然后再运⾏Java程序,这样既不会使程序变⼤,也不会使中⽂变味,可是⽤了⼀段时间⼜发现问题了,处理过程中如果遇到偏僻的中⽂字,还是乱码,原因是AIX的中⽂环境使⽤的字符集是IBM-eucCN,我认为可能是这个字符集缺少偏僻汉字,⽆法解释其内容,所以偏僻字变成了乱码了。
最后的解决办法是,在Windows中⽂环境下正常编写原程序,⽤默认的⽅式编译⽣成class⽂件,或者编译时指定参数-encoding
GB18030,这样汉字都能正常解释并转换为UTF-8存储在class⽂件中,在运⾏的时候,我们需要制定参数,java –
出问题,⽽且还解决了偏僻字的显⽰问题。
结论是,如果是源代码乱码,原因是保存源代码的时候的编码⽅式与打开源代码的时候的编码⽅式不⼀致,这时只需要转换编辑器的编码⽅式与保存时候的编码⽅式⼀致即可解决乱码问题;如果是编译的时候出现乱码,javac会使⽤系统当前的默认字符集去读取源⽂件,所以需要将编码⽅式改为系统默认的编码⽅式;如果是运⾏时产⽣乱码,就需要在运⾏java程序的时候加上指令java –ding= **(运⾏平台的默认字符集)即可
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论