结论:如果后台数据采用UNICODE方式的存储然后根据需要指定字符集编码、解码方式,则应用几乎可以不受前端应用所处环境字符集设置的影响
试验2的一些结论:
所有的应用都是按照字节流=>字符流=>字节流方式进行的处理的:
byte_stream ==[input decoding]==> unicode_char_stream ==[output encoding]==> byte_stream;
在Java字节流到字符流(或者反之)都是含有隐含的解码处理的(缺省是按照系统缺省编码方式);
最早的字节流解码过程从javac的代码编译就开始了;
Java中的字符character存储单位是双字节的UNICODE;
试验3:WEB应用中的输入输出中的编码问题:Java是为做国际化应用设计的,Servlet应根据浏览器语言设置自动切换字符集配置
首先一个概念:即使是基于Java的WEB应用,在服务器和客户端之间传递的仍然是字节流,比如我从一个中文客户端的浏览器表单中提交“世界你好”这4个中文字到服务器时:首先浏览器按照GBK方式编码成字节流CA C0 BD E7 C4 E3 BA C3,然后8个字节按照URLEncoding的规范转成:%CA%C0%BD%E7%C4%E3%BA%C3,服务器端的Servlet接收到请求后应该按什么解码处理,输出时又应该按什么方式编码行字节流呢?
在目前的Servlet的规范中,如果不指定的话通过WEB提交时的输入ServletRequest和输出时的ServletResponse缺省都是ISO-8859-1方式编/码解码的(注意,这里的编码/解码方式是和操作系统环境中的语言环境是无关的)。因此,即使服务器操作系统的语言环境是中文,上面输入的请求仍然按英文解码成8个UNICODE字符,输出时仍按照英文再编码成8个字节,虽然这样在浏览器端如果设置是中文能够正确显示,但实际上读写的是“字节”,正确的方式是应该根据客户端浏览器设置ServletRequest和ServletResponse用相应语言的编码方式进行输入解码/输入编码,HelloUnicodeServlet.java就是这样一个监测客户端浏览器语言设置的例子:
当根据浏览器的头信息中的"Accept-Language"为zh-cn(中文)时,设置请求的解码方式和输出的字符集编码方式使用GBK:
//auto detect broswer’s languages String clientLanguage = req.getHeader("Accept-Language"); //for Simplied Chinese if ( clientLanguage.equals("zh-cn") ) { req.setCharacterEncoding("GBK"); res.setContentType("text/html; charset=GBK"); }
输出为:
’世界你好’ length=4ServletRequest’s Charset Encoding = GBK ServletResponse’s Charset Encoding = GBK char[0]=’世’ byte=22 u16 short=19990 u4E16 CJK_UNIFIED_IDEOGRAPHSchar[1]=’界’ byte=76 u4C short=30028 u754C CJK_UNIFIED_IDEOGRAPHSchar[2]=’你’ byte=96 u60 short=20320 u4F60 CJK_UNIFIED_IDEOGRAPHSchar[3]=’好’ byte=125 u7D short=22909 u597D CJK_UNIFIED_IDEOGRAPHS
再做一个试验:把程序开头部分的浏览器自动检测功能注释掉,再次的输出结果就是和目前很多应用一样其实是按ISO-8859-1方式解码/编码的“字节应用”了:
’世界你好’ length=8ServletRequest’s Charset Encoding = null ServletResponse’s Charset Encoding = ISO-8859-1 char[0]=’? byte=-54 uFFFFFFCA short=202 uCA LATIN_1_SUPPLEMENTchar[1]=’? byte=-64 uFFFFFFC0 short=192 uC0 LATIN_1_SUPPLEMENTchar[2]=’? byte=-67 uFFFFFFBD short=189 uBD LATIN_1_SUPPLEMENTchar[3]=’? byte=-25 uFFFFFFE7 short=231 uE7 LATIN_1_SUPPLEMENTchar[4]=’? byte=-60 uFFFFFFC4 short=196 uC4 LATIN_1_SUPPLEMENTchar[5]=’? byte=-29 uFFFFFFE3 short=227 uE3 LATIN_1_SUPPLEMENTchar[6]=’? byte=-70 uFFFFFFBA short=186 uBA LATIN_1_SUPPLEMENTchar[7]=’? byte=-61 uFFFFFFC3 short=195 uC3 LATIN_1_SUPPLEMENT
虽然这样的输出结果如果在浏览器中设置用中文字符集也能正确显示,但实际上处理的已经是“字节”而不是处理中文“字符”了。ServletRequest 和 ServletResponse 缺省使用ISO-8859-1字符集解码/编码的具体定义请参考:
输入字节流 ==>按系统语言字符集设置将字节流解码==> UNICODE处理 ==> 按系统语言字符集设置将UNICODE编码成字节流 ==> 输出字节流
(服务器端或跨语言平台应用):在应用的最外端:数据输入输出判断用户语言环境,核心按照UNICODE方式处理存储。可以把各种区域性的字符集(GB2312 BIG5)看成是UNICODE的一个子集。UNICODE存储的数据可以方便的转换成任意字符集。
应用使用UTF8方式存储虽然要增加了存储空间,但也可以大大简化前端应用本地化(i10n)的复杂程度。
简体中文输入 繁体中文输入 简体中文输出 繁体中文输出 / / 判断用户语言环境:解码 判断用户语言环境:编码 / 中间处理过程:UNICODE | UTF8编码存储
随着UNICODE被愈来愈多的系统和平台支持:Python Perl Glibc等,但我们应该珍惜一开始就按照国际化规范设计Java,并将其和新发展起来的XML规范相配合,相信符合国际化规范的应用设计从长远来看会展现出更多的优势。
TODO:
数据库应用中的字符集问题试验:MySQL Oracle JDBC
参考文档:
Java的国际化设计
http://java.sun.com/docs/books/tutorial/i18n/index.html
Linux 国际化本地化和中文化
http://www.linuxforum.net/doc/i18n-new.html
Linux 程序员必读:中文化与GB18030标准
http://www.ccidnet.com/tech/os/2001/07/31/58_2811.html
Unicode FAQ
http://www.cl.cam.ac.uk/~mgk25/unicode.html
http://www.linuxforum.net/books/UTF-8-Unicode.html (中文版)
Java 编程技术中汉字问题的分析及解决
http://www-900.ibm.com/developerWor...ese/index.shtml
汉字的编码方式:
http://www.unihan.com.cn/cjk/ana17.htm
不同版本的JVM支持的编码方式
http://java.sun.com/j2se/1.3/docs/g...coding.doc.html
http://java.sun.com/j2se/1.4/docs/g...coding.doc.html