`
lvwenwen
  • 浏览: 930825 次
  • 性别: Icon_minigender_1
  • 来自: 魔都
社区版块
存档分类
最新评论

为什么JAVA会产生乱码

阅读更多
在计算机中,只有二进制的数据,不管数据是在内存中,还是在外部存储设备上。对于我们所看到的字符,也是以二进制数据的形式存在的。不同字符对应二进制数的规则,就是字符的编码。字符编码的集合称为字符集。

常用字符集

在早期的计算机系统中,使用的字符非常少,这些字符包括26个英文字母、数字符号和一些常用符号(包括控制符号),对这些字符进行编码,用1个字节就足够了(1个字节可以表示28=256种字符)。然而实际上,表示这些字符,只使用了1个字节的7位,这就是ASCII编码1.ASCII

ASCII(American Standard Code for Information Interchange,美国信息互换标准代码),是基于常用的英文字符的一套电脑编码系统。每一个ASCII码与一个8位(bit)二进制数对应。其最高位是0,相应的十进制数是0~127。例如,数字字符“0”的编码用十进制数表示就是48。另有128个扩展的ASCII码,最高位都是1,由一些图形和画线符号组成。ASCII是现今最通用的单字节编码系统。

ASCII用一个字节来表示字符,最多能够表示256种字符。随着计算机的普及,许多国家都将本地的语言符号引入到计算机中,扩展了计算机中字符的范围,于是就出现了各种不同的字符集。

2.ISO8859-1

因为ASCII码中缺少£、ü和许多书写其他语言所需的字符,为此,可以通过指定128以后的字符来扩展ASCII码。国际标准组织(ISO)定义了几个不同的字符集,它们是在ASCII码基础上增加了其他语言和地区需要的字符。其中最常用的是ISO8859-1,通常叫做Latin-1。Latin-1包括了书写所有西方欧洲语言不可缺少的附加字符,其中0~127的字符与ASCII码相同。ISO 8859另外定义了14个适用于不同文字的字符集(8859-2到8859-15)。这些字符集共享0~127的ASCII码,只是每个字符集都包含了128~255的其他字符。

3.GB2312和GBK

GB2312是中华人民共和国国家标准汉字信息交换用编码,全称《信息交换用汉字编码字符集-基本集》,标准号为GB2312-80,是一个由中华人民共和国国家标准总局发布的关于简化汉字的编码,通行于中国大陆和新加坡,简称国标码。

因为中文字符数量较多,所以采用两个字节来表示一个字符,分别称为高位和低位。为了和ASCII码有所区别,中文字符的每一个字节的最高位都用1来表示。GB2312字符集是几乎所有的中文系统和国际化的软件都支持的中文字符集,也是最基本的中文字符集。它包含了大部分常用的一、二级汉字和9区的符号,其编码范围是高位0xa1-0xfe,低位也是0xa1-0xfe,汉字从0xb0a1开始,结束于0xf 7fe。

为了对更多的字符和符号进行编码,由前电子部科技质量司和国家技术监督局标准化司于1995年12月颁布了GBK(K是“扩展”的汉语拼音第一个字母)编码规范,在新的编码系统里,除了完全兼容GB2312外,还对繁体中文、一些不常用的汉字和许多符号进行了编码。它也是现阶段Windows和其他一些中文操作系统的默认字符集,但并不是所有的国际化软件都支持该字符集。不过要注意的是GBK不是国家标准,它只是规范。GBK字符集包含了20 902个汉字,其编码范围是0x8140-0xfefe。

每个国家(或区域)都规定了计算机信息交换用的字符编码集,这就造成了交流上的困难。想像一下,你发送一封中文邮件给一位远在西班牙的朋友,当邮件通过网络发送出去的时候,你所书写的中文字符会按照本地的字符集GBK转换为二进制编码数据,然后发送出去。当你的朋友接收到邮件(二进制数据)后,查看信件时,会按照他所用系统的字符集,将二进制编码数据解码为字符,然而由于两种字符集之间编码的规则不同,导致转换出现乱码。这是因为,在不同的字符集之间,同样的数字可能对应了不同的符号,也可能在另一种字符集中,该数字没有对应符号。

为了解决上述问题,统一全世界的字符编码,由Unicode协会制定并发布了Unicode编码。

4.Unicode

Unicode(统一的字符编码标准集)使用0~65 535的双字节无符号数对每一个字符进行编码。它不仅包含来自英语和其他西欧国家字母表中的常见字母和符号,也包含来自古斯拉夫语、希腊语、希伯来语、阿拉伯语和梵语的字母表。另外还包含汉语和日语的象形汉字和韩国的Hangul音节表。

目前已经定义了40 000多个不同的Unicode字符,剩余25 000个空缺留给将来扩展使用。其中大约20 000个字符用于汉字,另外11 000左右的字符用于韩语音节。Unicode中0~255的字符与ISO8859-1中的一致。

Unicode编码对于英文字符采取前面加“0”字节的策略实现等长兼容。如“a”的ASCII码为0x61,Unicode码就为0x00,0x61。

5.UTF-8

使用Unicode编码,一个英文字符要占用两个字节,在Internet上,大多数的信息都是用英文来表示的,如果都采用Unicode编码,将会使数据量增加一倍。为了减少存储和传输英文字符数据的数据量,可以使用UTF-8编码。

UTF-8全称是Eight-bit UCS Transformation Format(UCS,Universal Character Set,通用字符集,UCS是所有其他字符集标准的一个超集)。对于常用的字符,即0~127的ASCII字符,UTF-8用一个字节来表示,这意味着只包含7位ASCII字符的字符数据在ASCII和UTF-8两种编码方式下是一样的。如果字符对应的Unicode码是0x0000,或在0x0080与0x007f之间,对应的UTF-8编码是两个字节,如果字符对应的Unicode码在0x0800与0xffff之间,对应的UTF-8编码是三个字节。因为中文字符的Unicode编码在0x0800与0xffff之间,所以数据如果是中文,采用UTF-8编码数据量会增加50%。

Unicode与UTF-8转换的规则简述如下:

(1)如果Unicode编码的16位二进制数的前9位是0,则UTF-8编码用1个字节来表示,这个字节的首位是“0”,剩下的7位与原二进制数据的后7位相同。例如:

Unicode编码:\u0061 = 00000000 01100001

UTF-8编码:01100001 = 0x61

(2)如果Unicode编码的16位二进制数的头5位是0,则UTF-8编码用2个字节来表示,首字节以“110”开头,后面的5位与原二进制数据除去前5个零后的最高5位相同;第二个字节以“10”开头,后面的6位与原二进制数据中的低6位相同。例如:

Unicode编码:\u00A9 = 00000000 10101001

UTF-8编码:11000010 10101001 = 0xC2 0xA9

(3)如果不符合上述两个规则,则用三个字节表示。第一个字节以“1110”开头,后四位为原二进制数据的高四位;第二个字节以“10”开头,后六位为原二进制数据中间的六位;第三个字节以“10”开头,后六位为原二进制数据的低六位。例如:

Unicode编码:\u4E2D = 01001110 00101101

UTF-8编码:11100100 10111000 10101101 = 0xE4 0xB8 0xAD

在UTF-8编码的多字节串中,第一个字节开头“1”的数目就是整个字符串中字节的数目。

17.1.2 对乱码产生过程的分析

为了让使用Java语言编写的程序能在各种语言的平台下运行,Java在其内部使用Unicode字符集来表示字符,这样就存在Unicode字符集和本地字符集进行转换的过程。当在Java中读取字符数据的时候,需要将本地字符集编码的数据转换为Unicode编码,而在输出字符数据的时候,则需要将Unicode编码转换为本地字符集编码。

例如,在中文系统下,从控制台读取一个字符“中”,实际上读取的是“中”的GBK编码0xD6D0,在Java语言中要将GBK编码转换为Unicode编码0x4E2D,此时,在内存中,字符“中”对应的数值就是0x4E2D,当我们向控制台输出字符时,Java语言将Unicode编码再转换为GBK编码,输出到控制台,中文系统再根据GBK字符集画出相应的字符。

从上述过程来看,读取和写入的过程是可逆的,那么理应不会出现中文乱码问题。然而,实际应用的情形,比上述过程要复杂得多。在Web应用中,通常都包括了浏览器、Web服务器、Web应用程序和数据库等部分,每一部分都有可能使用不同的字符集,从而导致字符数据在各种不同的字符集之间转换时,出现乱码的问题。

在Java语言中,不同字符集编码的转换,都是通过Unicode编码作为中介来完成的。例如,GBK编码的字符“中”要转换为ISO-8859-1(同ISO8859-1)编码,其过程如下:

(1)因为在Java中的字符,都是用Unicode来表示的,所以GBK编码的字符“中”要转换为Unicode表示:0xD6D0->0x4E2D。

(2)将字符“中”的Unicode编码转换为ISO-8859-1编码,因为Unicode编码0x4E2D在ISO-8859-1中没有对应的编码,于是得到0x3f,也就是字符“?”。

下面的代码演示了这一过程:

//GBK编码的字符“中”转换为Unicode编码表示

String str="中";

//将字符“中”的Unicode编码转换为ISO-8859-1编码

byte[] b=str.getBytes("ISO-8859-1");



for(int i=0;i<b.length;i++)

{

       //输出转换后的二进制代码。

       System.out.print(b[i]);

}

当从Unicode编码向某个字符集转换时,如果在该字符集中没有对应的编码,则得到0x3f(即问号字符?)。这就是为什么有时候我们输入的是中文,在输出时却变成了问号。

从其他字符集向Unicode编码转换时,如果这个二进制数在该字符集中没有标识任何的字符,则得到的结果是0xfffd。例如一个GBK的编码值0x8140,从GB2312向Unicode转换,然而由于0x8140不在GB2312字符集的编码范围(0xa1a1-0xfefe),当然也就没有对应任何的字符,所以转换后会得到0xfffd。下面的代码演示了这一过程。

//构造一个二进制数据。

byte[] buf={(byte)0x81,(byte)0x40,(byte)0xb0,(byte)0xa1};

//将二进制数据按照GB2312向Unicode编码转换。

String str=new String(buf,"GB2312");

      

for(int i=0;i<str.length();i++)

{

    //取出字符串中的每个Unicode编码的字符。

    char ch=str.charAt(i);

    //将该字符对应的Unicode编码以十六进制的形式输出。

    System.out.print(Integer.toHexString((int)ch));

    System.out.print("--");

    //输出该字符。

    System.out.println(ch);

}
分享到:
评论

相关推荐

    Java乱码问题解决

    在Java编程中,经常会碰到汉字的处理及显示问题,以不小心就会产生一大堆乱码或者问号。造成这种问题的根本原因是Java中默认的编码方式是Unicode,而中国人通常使用的文件和DB都是基于GB2312或BIG5等编码,故会出现...

    java中的中文乱码与汉字革命

    java中的中文乱码(其中介绍了中国近现代的汉字革命) java中为什么会产生中文乱码 如何解决java中的中文乱码

    java解压乱码问题修正

    JAVA中文件压缩引起的乱码问题,是由于Java编码以Unicode 为基础的,所以ZipOutputStream(还有... 所以为了能在压缩(或解压)时,不让其产生乱码问题,就得修改ZipOutputStream(ZipInputStream)中的编码方式。

    Java编程汉字乱码原因分析及解决方法研究.pdf

    java程序输入输出汉字时常常出现乱码现象,针对这一异常,本文首先介绍了java和JSP文件编译时对汉字字符处理的基本原理,接着分析了java程序与其他媒介交互时产生乱码现象的根本原因,最后针对产生异常的每种情况给出了...

    Java Web开发中文乱码问题的研究与解决.pdf

    在利用Servlet/JSP技术开发java Web应用程序的时候,不可避免的会遇到中文乱码问题,本文首先介绍了Web应用中常用的编码方式,然后分析了J2EE平台下Web应用中文乱码问题产生的原因,并在此基础上针对不同情况提出了解决...

    java代码产生汉字库

    java代码实现汉字库,编码方式有GB2312,GBK,Unicode,UTF-8,利用以上编码规则产生汉字库,目前是第一版本,只产生汉字库,第二版本实现随机汉字验证码,根据拼音检索匹配的汉字.

    java中文乱码字符集解决大全

    Abstract:本文深入分析了Java程序设计中Java编译器对java源文件和JVM对class类文件的编码/解码过程,通过此过程的解析透视出了Java编程中中文问题产生的根本原因,最后给出了建议的最优化的解决Java中文问题的方法...

    org.apache.tools.zip解决解压乱码问题

    * @param zipFileName 压缩产生的zip包文件名--带路径,如果为null或空则默认按文件名生产压缩文件名 * @param relativePath 相对路径,默认为空 * @param directory 文件或目录的绝对路径 * void */ ...

    Java Web开发中中文乱码问题的分析与解决方法 (1).pdf

    从介绍java常用字符编码集入手,详细分析了在java Web开发中产生中文乱码的原因,并针对原因提出了可行性解决方法。

    Java Web应用开发中的中文乱码问题研究.pdf

    在java Web应用开发中,软件开发人员最容易遇到的问题就是中文的乱码问题,其中最常见的有两种,JSP页面中文显示乱码和表单提交参数中文乱码。本文通过深入分析这两种中文乱码问题产生的原因,分别给出了对应的解决方案...

    Java Web开发中的乱码问题分析及解决方案研究 (1).pdf

    在利用JSP/Servlet技术开发java Web应用程序的时候,经常会遇到中文乱码问题,本文首先介绍了Web应用中常见的编码方式,然后分析了J2EE平台下Web应用中文乱码产生的原因,并针对不同情况给出了解决方法。

    Java编程中中文问题的产生及其解决方案.pdf

    在深入分析java程序设计中java编译器对java源文件和JVM对class文件的编码/解码过程的基础上,分析java编程中中文问题产生的根本原因,同时给出常见的java程序在解决中文乱码方面的建议解决方案。

    Java工具包将Excel(xls、xlsx)格式转换为csv格式文件Linux、Window环境均可使用

    对Excel类型文件(xls,xlsx)进行批量转换CSV格式,完成文件格式无损转换,在Linux系统,通过view或其他命令查看xls、xlsx文件时会产生乱码,使用view查看csv文件不会产生乱码,因为csv格式文件是由空格和逗号进行...

    JD-GUI Java反编译器

    java反编译软件 产生的代码都是纯代码 无乱码产生 java反编译软件 产生的代码都是纯代码 无乱码产生

    Java加密金盾v1.01

    一款对Java编译的class进行加密的软件,功能强大,可以很方便对class文件进行数据加密产生新的文件来代替,然后再用本软件提供的启动入口运行加密过后的class。加密过后的class文件是乱码,这时采用任何反编译工具都...

    java调用微信小程序API createwxaqrcode 产生二维码

    调用产生二维码的接口一直乱码,一直没想出为什么乱码,囧,郁闷之极,还好九爷慷慨分享了文章,得知返回的是二进制,createwxaqrcode接口并不复杂,只是在官方接口并没声明返回内容,只要知道返回的内容就好办了,...

    jxl.jar原版、修改后的jxl.jar解决web dynpro中乱码问题

    jxl.jar在web dynpor中读取Excel文件时,会导致乱码的产生,修改这个包中的java文件后就可以解决

    关于jsp字符乱码的处理

    分情况对jsp乱码的产生进行总结和处理 包括数据库乱码和服务器乱码的解决

    JavaWeb应用中文乱码的解决方案 (1).pdf

    分析了java Web应用中产生中文乱码的原因,归纳总结了产生中文乱码的几种情况,根据每种情况给出了多种解决方案,并分析了每种解决方案各自的优缺点以及适用场合,为java Web程序员提供了参考和借鉴。

    JAVA自学之路

    有不少的同学发信给我,和我探讨java的自学过程应该是什么样的,毕竟有很多人因为各种各样的原因不能参加培训。我试着给出自己的见解,抛砖引玉吧。 这个路线图是给那些为了就业的人准备的,如果只是兴趣,不一定照...

Global site tag (gtag.js) - Google Analytics