Java各种中⽂乱码问题及解决⽅案
问题的根源
Java的内核和class⽂件是基于unicode的,这使Java程序具有良好的跨平台性,但也带来了⼀些中⽂乱码问题的⿇烦。原因主要有两⽅⾯,Java和JSP⽂件本⾝编译时产⽣的乱码问题和Java程序于其他媒介交互产⽣的乱码问题。
  ⾸先Java(包括JSP)源⽂件中很可能包含有中⽂,⽽Java和JSP源⽂件的保存⽅式是基于字节流的,如果Java和JSP编译成 class⽂件过程中,使⽤的编码⽅式与源⽂件的编码不⼀致,就会出现乱码。基于这种乱码,建议在Java⽂件中尽量不要写中⽂(注释部分不参与编译,写中⽂没关系),如果必须写的话,尽量⼿动带参数-encoding GBK或-encoding gb2312编译;对于JSP,在⽂件头加上或基本上就能解决这类乱码问题。
问题的种类
即Java程序与其他存储媒介交互时产⽣的乱码。很多存储媒介,如数据库,⽂件,流等的存储⽅式都是基于字节流的,Java程序与这些媒介交互时就会发⽣字符(char)与字节(byte)之间的转换,具体情况如下:
(1)从页⾯form提交数据到java程序 byte->char
(2)从java程序到页⾯显⽰ char-->byte
(3)从数据库到java程序 byte-->char
(4)从java程序到数据库 char-->byte
(5)从⽂件到java程序 byte->char
(6)从java程序到⽂件 char->byte
如果在以上转换过程中使⽤的编码⽅式与字节原有的编码不⼀致,很可能就会出现乱码。
基础——了解字符集
(1)ASCII
ASCII码是7位编码,编码范围是0x00-0x7F。ASCII字符集包括英⽂字母、阿拉伯数字和标点符号等字符。其中0x00-0x20和0x7F共33个控制字符。
只⽀持ASCII码的系统会忽略每个字节的最⾼位,只认为低7位是有效位。HZ字符编码就是早期为了在只⽀持7位ASCII系统中传输中⽂⽽设计的编码。早期很多邮件系统也只⽀持ASCII编码,为了传输中⽂邮件必须使⽤BASE64或者其他编码⽅式。
(2)GB2312
GB2312 是基于区位码设计的,区位码把编码表分为94个区,每个区对应94个位,每个字符的区号和位号组合起来就是该汉字的区位码。区位码⼀般⽤10进制数来表⽰,如1601就表⽰16区1位,对应的字符是“啊”。在区位码的区号和位号上分别加上0xA0就得到了
GB2312编码。
区位码中01-09区是符号、数字区,16-87区是汉字区,10-15和88-94是未定义的空⽩区。它将收录的汉字分成两级:第⼀级是常⽤汉字计 3755个,置于16-55区,按汉语拼⾳字母/笔形顺序排列;第⼆级汉字是次常⽤汉字计3008个,置于56-87区,按部⾸/笔画顺序排列。⼀级汉字 是按照拼⾳排序的,这个就可以得到某个拼⾳在⼀级汉字区位中的范围,很多根据汉字可以得到拼⾳的程序就是根据这个原理编写的。
GB2312字符集中除常⽤简体汉字字符外还包括希腊字母、⽇⽂平假名及⽚假名字母、俄语西⾥尔字母
等字符,未收录繁体中⽂汉字和⼀些⽣僻字。可以⽤繁体汉字测试某些系统是不是只⽀持GB2312编码。
区位码更应该认为是字符集的定义,定义了所收录的字符和字符位置,⽽GB2312及EUC-CN是实际计算机环境中⽀持这种字符集的编码。HZ和ISO-2022-CN是对应区位码字符集的另外两种编码,都是⽤7位编码空间来⽀持汉字。区位码和GB2312编码的关系有点像Unicode和UTF-8。
(3)GBK
GBK 编码是GB2312编码的超集,向下完全兼容GB2312,同时GBK收录了Unicode基本多⽂种平⾯中的所有CJK汉字。同 GB2312⼀样,GBK也⽀持希腊字母、⽇⽂假名字母、俄语字母等字符,但不⽀持韩语中的表⾳字符(⾮汉字字符)。GBK还收录了GB2312不包含的汉字部⾸符号、竖排标点符号等字符。
GBK编码是中国⼤陆制订的、等同于UCS的新的中⽂编码扩展国家标准。GBK⼯作⼩组于1995年10⽉,同年12⽉完成GBK规范。该编码标准兼容GB2312,共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于⼀库。
(4)GB18030
GB18030编码向下兼容GBK和GB2312,兼容的含义是不仅字符兼容,⽽且相同字符的编码也相同。GB18030收录了所有Unicode3.1中的字符,包括中国少数民族字符,GBK不⽀持的韩⽂字符等等,也可以说是世界⼤多民族的⽂字符号都被收录在内。
GBK和GB2312都是双字节等宽编码,如果算上和ASCII兼容所⽀持的单字节,也可以理解为是单字节和双字节混合的变长编码。
GB18030编码是变长编码,有单字节、双字节和四字节三种⽅式。
GB18030 的单字节编码范围是0x00-0x7F,完全等同与ASCII;双字节编码的范围和GBK相同,⾼字节是0x81-0xFE,低字节的编码范围是 0x40-0x7E和0x80-FE;四字节编码中第⼀、三字节的编码范围是0x81-0xFE,⼆、四字节是0x30-0x39。
Windows 中CP936代码页使⽤0x80来表⽰欧元符号,⽽在GB18030编码中没有使⽤0x80编码位,⽤其他位置来表⽰欧元符号。这可以理解为是 GB18030向下兼容性上的⼀点⼩问题;也可以理解为0x80是CP936对GBK的扩展,⽽GB18030只是和GBK兼容良好。
(5)unicode
每⼀种语⾔的不同的编码页,增加了那些需要⽀持不同语⾔的软件的复杂度。因⽽⼈们制定了⼀个世
界标准,叫做unicode。unicode为每个字符提供 了唯⼀的特定数值,不论在什么平台上、不论在什么软件中,也不论什么语⾔。也就是说,它世界上使⽤的所有字符都列出来,并给每⼀个字符⼀个唯⼀特定数值。
   Unicode的最初⽬标,是⽤1个16位的编码来为超过65000字符提供映射。但这还不够,它不能覆盖全部历史上的⽂字,也不能解决传输的问题,尤其在那些基于⽹络的应⽤中。已有的软件必须做⼤量的⼯作来程序16位的数据。
  因此,Unicode⽤⼀些基本的保留字符制定了三套编码⽅式。它们分别是UTF-8,UTF-16和UTF-32。正如名字所⽰,在UTF-8中,字符是 以8位序列来编码的,⽤⼀个或⼏个字节来表⽰⼀个字符。这种⽅式的最⼤好处,是UTF-8保留了ASCII字符的编码做为它的⼀部分,例如,在UTF-8 和ASCII中,’A’的编码都是0x41.
UTF-16和UTF-32分别是Unicode的16位和32位编码⽅式。考虑到最初的⽬的,通常说的Unicode就是指UTF-16。在讨论Unicode 时,搞清楚哪种编码⽅式⾮常重要。
(6)UTF-8
Unicode Transformation Format-8bit,允许含BOM,但通常不含BOM。是⽤以解决国际上字符的⼀种
多字节编码,它对英⽂使⽤8位(即⼀个字节),中⽂使⽤24位(三个字节)来编码。UTF-8包含全世界所有国家需要⽤到的字符,是国际编码,通⽤性强。UTF-8编码的⽂字可以在各国⽀持UTF8字符集的浏览器上显 ⽰。如,如果是UTF8编码,则在外国⼈的英⽂IE上也能显⽰中⽂,他们⽆需下载IE的中⽂语⾔⽀持包。
GBK的⽂字编码是⽤双字节来表⽰的,即不论中、英⽂字符均使⽤双字节来表⽰,为了区分中⽂,将其最⾼位都设定成1。GBK包含全部中⽂字符,是国家编码,通⽤性⽐UTF8差,不过UTF8占⽤的数据库⽐GBD⼤。
GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换:
GBK、GB2312--Unicode--UTF8
UTF8--Unicode--GBK、GB2312
对于⼀个⽹站、论坛来说,如果英⽂字符较多,则建议使⽤UTF-8节省空间。不过现在很多论坛的插件⼀般只⽀持GBK。
解决⽅法
(1)JSP页⾯显⽰乱码
这种乱码的原因是应为没有在页⾯⾥指定使⽤的字符集编码,解决⽅法:只要在页⾯开始地⽅⽤下⾯代码指定字符集编码即可
(2)表单提交中⽂时出现乱码
JSP获取页⾯参数时⼀般采⽤系统默认的编码⽅式,如果页⾯参数的编码类型和系统默认的编码类型不⼀致,很可能就会出现乱码。解决这类乱码问题的基本⽅法是在页⾯获取参数之前,强制指定request获取参数的编码⽅式:request.setCharacterEncoding("GBK")或request.setCharacterEncoding("gb2312")。
当然,使⽤下列⽅式亦可:、
String name = Parameter(“name”);
name = new Bytes(“iso-8859-1”),”gb2312”);
如果在JSP将变量输出到页⾯时出现了乱码,可以通过设置
response.setContentType("text/html;charset=GBK")
response.setContentType("text/html;charset=gb2312")解决。
(3)数据库连接出现乱码
这种乱码会使你插⼊数据库的中⽂变成乱码,或者读出显⽰时也是乱码,解决⽅法如下:
  在数据库连接字符串中加⼊编码字符集
  String Url="jdbc:mysql://localhost/database?
user=root&password=root&useUnicode=true&characterEncoding=GB2312";
(4)数据库的显⽰乱码
第⼀步:写⼀个转换字符串的公共类
public class StringConvert {
public static String Convert(String s)
{
String gb;
try{
if(s.equals("") || s == null){
return "";
}
else{
s  = s.trim();
gb = new Bytes("ISO-8859-1"),"GBK");
return gb;
}
java和jsp
}
catch(Exception e){
return "";
}
}
}
第⼆步:解决MySQL的中⽂问题
⽅法1、
打开MySQL客户端(MySQL command Line Client),设置以下三项:
set character_set_client=gbk;
set character_set_results=gbk;
set character_set_connection=gbk;
之后,再将MySQL安装⽬录下的my.ini⽂件中的:default-character-set的值设为gbk(注意有两处需要修改)。
注1:这种⽅法有个缺陷就是,修改后,在新建表中的乱码消失了,但是在原先的表中却⼜出现了乱码;解的办法是,先将原先的表中的数据导出,修改后,再重建表,最后再将数据导⼊。
注2:有关character_set_client等等的作⽤,
⽅法2、
在安装MySQL的时候稍微留⼼⼀下编码的设置,将其设置为GBK⼀切OK,这样就省去了以后的⿇烦。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。