一直以来,就有个不大正确的观念,也导致中文问题困扰了我很久,所谓错误观念就是“中文占2个字节,英文数字占1个字节”。现在明白,其实这样子说法是有条件的。
其中参考了几篇文章,以下也只是对文章的总结和笔记。
《从 汉化 到 国际化》
《深入剖析JSP和Servlet对中文的处理》
《Java中文问题详解》
关于字符编码
具体可以参见:http://yeyongq.spaces.live.com/Blog/cns!A52629657552983C!1728.entry?owner=1
其实在网上关于字符编码的文章很多,其实各个常用字符集是如下关系:
gb2312是一个小的中文集,大概支持6000多个字,中文为2字节;
gbk是gb2312扩展,基本涵盖了大部分的中文字,中文为2字节;
两个针对全人类所有字符的编码字符集,一个是
UCS
(Universal Character Set
),它是国际标准化组织弄出来的,也就是ISO/IEC 10646;另一个是
Unicode
(Universal Code
),Unicode同时也是一个联盟的名字,也就是HP、Microsoft、IBM、Apple等几家知名的大型计算企业所组成的联盟集团,他们为了推进多种文种的统一编码而制定出了Unicode。
UTF-8则是为了解决Unix下使用Unicode而设计的,它是在 Unix 风格的操作系统下使用 Unicode 的明显的方法,中文为3字节。(http://www.linuxforum.net/books/UTF-8-Unicode.html)
Java中String和Char的区别
在Java中支持Unicode,因此一个char占了2 bytes,也即16bit。因此可以放得下一个中文字:
char a = '你';
char b = 'y';
都是合法的。
而String.getBytes()方法,则是要根据系统默认的字符集编码返回bytes,为了有更好的实用性,最好还是使用.getBytes("字符集")的格式。对于String c = "你"的情况,GBK会返回2个byte,UTF-8会返回3个byte.
操作系统对JVM编码的影响
《Java的中文处理学习笔记》中讲到的比较全面,可以归纳为:JVM的默认字符编码集与操作系统设置有关。在
System.getProperties中的file.encoding就是根据操作系统的设置而变化的。
在Linux下,LANG=zh_CN; LC_ALL=zh_CN.GBK; export LANG LC_ALL 设置。(还未测试过)
在Windows下,使用区域设置。
javac -encoding的影响
编译器就是根据这个变量来读取java文件的,然后把用UTF-8形式编译成class文件。 也就是说-encoding决定的只是如何读取源文件,而class总是以UTF-8格式编译的。
JSP/Servlet中文的影响
可以参见《深入剖析JSP和Servlet对中文的处理》,其中提到了3个概念:
Complier-charset 就是指的javac -encoding的字符集
Servlet-charset, 指的是HttpServletResponse.setContentType(),即返回时指定浏览器使用的字符集
Jsp-charset,只用于jsp页面上,<%@ page contentType="text/html; charset=utf-8" %>,对于指定了这个属性的jsp文件,Complier-charset 和Servlet-charset都被指定为jsp-charset,上例:指定两者的都是utf-8。
文章中提到对于Complier和Servlet两者指定不同的charset会有乱码的情况,我认为指的是Servlet里有中文的情况才会出现,处理中文是不会有乱码的。因为编译器用A编码读取java文件,编译成UTF-8格式的class,运行时,如果返回给用户浏览器指定的是B编码,当然会有乱码的情况。
我理解是,用了jsp-charset,然后保证文本文件的编码和其相同,就可以保证页面上静态的中文会没有问题。我们经常会看到ISO8859-1,是因为英文操作系统中,不指定编码时,默认是此编码
浏览器对字符集编码的影响
IE中,对于中文参数的发送,都是将其转换为UTF格式,并送入传输流中,而Servlet会先用readUTF读取传输流。针对中文参数造成的乱码以及参数中有特殊字符,可以考虑用java.netURLEncoder.encode(String,String),指定编码方式后,再传输。如果在Servlet中,可以通过request.setCharacterEncoding,来指定UTF读取后用何种方式解码。
转载一下:自己认为对这个过程描述得比较清晰的文章,《JAVA字符集》里提到:
rlrb;A
“3.4.1. 表单输入
User input *(gbk:d6d0 cec4) browser *(gbk:d6d0 cec4) web server iso8859-1(00d6 00d 000ce 00c4) class,需要在class中进行处理:getbytes("iso8859-1")为d6 d0 ce c4,new String("gbk")为d6d0 cec4,内存中以unicode编码则为4e2d 6587。
l 用户输入的编码方式和页面指定的编码有关,也和用户的操作系统有关,所以是不确定的,上例以gbk为例。
l 从browser到web server,可以在表单中指定提交内容时使用的字符集,否则会使用页面指定的编码。而如果在url中直接用?的方式输入参数,则其编码往往是操作系统本身的编码,因为这时和页面无关。上述仍旧以gbk编码为例。
l Web server接收到的是字节流,默认时(getParameter)会以iso8859-1编码处理之,结果是不正确的,所以需要进行处理。但如果预先设 置了编码(通过request. setCharacterEncoding ()),则能够直接获取到正确的结果。
l 在页面中指定编码是个好习惯,否则可能失去控制,无法指定正确的编码。
3.4.2. 文件编译
假设文件是gbk编码保存的,而编译有两种编码选择:gbk或者iso8859-1,前者是中文windows的默认编码,后者是linux的默认编码,当然也可以在编译时指定编码。
Jsp *(gbk:d6d0 cec4) java file *(gbk:d6d0 cec4) compiler read uincode(gbk: 4e2d 6587; iso8859-1: 00d6 00d 000ce 00c4) compiler write utf(gbk: e4b8ad e69687; iso8859-1: *) compiled file unicode(gbk: 4e2d 6587; iso8859-1: 00d6 00d 000ce 00c4) class。所以用gbk编码保存,而用iso8859-1编译的结果是不正确的。
class unicode(4e2d 6587) system.out / jsp.out gbk(d6d0 cec4) os console / browser。
l 文件可以以多种编码方式保存,中文windows下,默认为ansi/gbk。
l 编译器读取文件时,需要得到文件的编码,如果未指定,则使用系统默认编码。一般class文件,是以系统默认编码保存的,所以编译不会出问题,但对于 jsp文件,如果在中文windows下编辑保存,而部署在英文linux下运行/编译,则会出现问题。所以需要在jsp文件中用 pageEncoding指定编码。
l Java编译的时候会转换成统一的unicode编码处理,最后保存的时候再转换为utf编码。
l 当系统输出字符的时候,会按指定编码输出,对于中文windows下,System.out将使用gbk编码,而对于response(浏览器),则使用 jsp文件头指定的contentType,或者可以直接为response指定编码。同时,会告诉browser网页的编码。如果未指定,则会使用 iso8859-1编码。对于中文,应该为browser指定输出字符串的编码。
l browser显示网页的时候,首先使用response中指定的编码(jsp文件头指定的contentType最终也反映在response上),如果未指定,则会使用网页中meta项指定中的contentType。 ”
总结一下,就是浏览器这端和操作系统和页面指定编码有关,发送时,是可以指定为以UTF-8发送的,服务器接受时,例如Tomcat,默认会以ISO_8859处理,这是英文操作系统默认的编码方式。
Tomcat5.0与4.0对编码的影响
参考《
Tomcat和STRUTS中的中文问题》,简单来说,就是4.0,可以用request.setCharacterEncoding在getParameter之前指定编码来解决。
但是,5.0以上,包括6.0,因为区分了GET和POST方法的处理,POST方法仍可以用setCharacterEncoding,但是GET方法则需要设定server.xml文件中URIEncoding参数,或者在程序中使用String.getBytes("ISO-8859-1")。
Weblogic对编码的影响
与Tomcat类似,通过设置setCharacterEncoding能解决大部分问题,而weblogic9默认的编码也是ISO-8859-1,如果要在URL中传输中文出现乱码,可以尝试String.getBytes("ISO-8859-1")
总结
这是一个比较大的题目,网上讨论的也很多,我看了之后,觉得比较实用的是以下几篇:
Java的中文处理学习笔记
JAVA字符集
Tomcat和STRUTS中的中文问题
Java/J2EE中文问题解决办法
深入剖析JSP和Servlet对中文的处理
有兴趣的可以分别看看,总结一下,较好的JAVA Web解决方法,应该是《Java/J2EE中文问题解决》中提到的用UTF-8结扎。指的是一下步骤:
1.确定编辑器使用的是UTF-8编码,保存文件
2.设定jsp-charset为UTF-8,这样就保证了源文件编译和服务器返回的编码都是UTF-8
3.如果遇到中文传送URL的话,应该先使用java.net.URLEncoding方法先编码再传输,接受时,如果设置了第1步,一般就不会乱码,如果真的遇上Tomcat5.0,那就再使用设置server.xml的URIEncoding属性,或者使用getBytes("ISO-8859-1"),因为一般的英文系统包括JAVA EE容器默认都是已这种格式处理字符。
F8e1E1"b
,pOmH2N5u
",*f$~qK
"1U9-gG
;nil`;Pg
tz& @dX
e}$_x0DQ
3/ 5
1At4}/L
]!Nzu~pk'
d.oA=A)
]/
Q.HVikJw
aw5*6y
Q$Ipu=w!
w@y<
#FYp_W`i
ttUJpr|
z$AXf`:.B
U$73=HH}
dYTV5H>A
]};uGzp8
ZG^.'Z
?39aW4%g
6 _^X@$IVD
sBrpJc
'KxUv$5x
vtCd6cl=c