`
kayo
  • 浏览: 557904 次
  • 性别: Icon_minigender_1
  • 来自: 安徽
社区版块
存档分类
最新评论

深入剖析字符集

阅读更多

anci.z(小谢), 2003.11.16
通过JDBC访问数据库时遇到的字符集问题中,可以归纳为如下因素:
- JVM对字符集的处理
JVM核心完全使用Unicode字符集,编码上采用UTF-16LE(x86和Unix)。 Java编译器
扫描.java源文件时将完成预转换,比如在中文Windows上编译.java文件时,你可能
已经注意到.java文件中的字符串和.class中的不一样。因为.java文件本身用的是
gb2312编码,而.class内则是UTF-16LE编码。如果你的编辑器支持,你可能会选择
直接用UTF-8来书写.java源程序,这时Java编译器就会用UTF-8对源程序解码。
在输出时,比如调用System.out.print方法也将完成一个编码转换,在上述情况中
经常是将内存中的UTF-16LE编码的字串转换成控制台上可读的gb2312编码。
- JSP页面使用的字符集
运行JSP页面前总会被预处理至.java程序并被编译成.class,注意到JSP总是一个
servlet,因此实际上这里存在两个字符集,一是.jsp文件本身使用的字符集,另一
则是servlet输出内容的字符集(content-type)。尽量使.jsp文件本身的字符集和输
出内容的字符集保持一致,比如一致采用UTF-8。Response的实现将jvm中的UTF-
16LE字串转换至<%@page encoding=...%>所指定的编码,
- Connection 使用的字符集
连接的字符集限制了SQL语句可以使用的字符。这在UTF-16中格外明显,如果连接不
使用UTF-16的字符集,那么由于大多数的Latin-1字符集对'\0'的处理将使大多数
SQL语句成为无效语句,比如SELECT语句通过UTF-16LE编码后将变
成"S\0E\0L\0E\0C\0T\0...",服务器的SQL分析器在遇到第一个'\0'便认为语句已经结束。
但仍然可以将UTF-16LE编码的字串送入Latin-1字符集的连接,方法是SQL语句本身
仍采用Latin-1编码,而相关的字串(引号内部的)采用UTF-16LE。这种情况下,UTF
-16LE的字串不能包括Unicode字符集中编码小于256的字符(包括拉丁字母和数字、
英文符号),否则SQL分析器会报告"字符串未结束"之类的错误。(为什么?)
- 数据库系统
并不是所有数据库都支持Unicode,你可能有必要通过字符集转换来保存一些特殊的
字符数据。如果数据库仅支持Latin-1字符集(这样的系统不在少数),对于中文的
情况,你可以将字符串用Latin-1编码,然后用gb2312解码,觉得困惑?如果你(曾
经)是C++程序员,那么这里的编码类似于dynamic_cast, 而解码则相当于
reinterpret_cast。
sql_str = new String( java_str.getBytes("ISO-8859-1"), "gb2312" );
在获取数据的时候则刚好相反:
java_str = new String( sql_str.getBytes("gb2312"), "ISO-8859-1" );
如果数据库系统支持Unicode,那么请尽量采用Unicode。有些手册上建议你根据具
体情况决定是否使用Unicode,因为Unicode将占用更多的存储空间,而且如果采用
UTF-8,排序的速度将会"减慢30% (mysql)",请不要为这些词语而顾虑,大多数情
况这些都不是问题。
对于SQL Server 2000,这篇文章值得一读:
http://www.microsoft.com/china/msdn/library/techart/IntlFeaturesInSQLServer2000.asp
最关键的就是你需要在字符串左边加上N字符(N一定要大写),如
INSERT INTO table(name_en, name_native) VALUES('yokohama', N' 横浜 ')
对于Sybase数据库(Sybase 11.5, Sybase 12),系统不支持UTF-16,但支持UTF-8,
为了使用Unicode,你可能需要下面的连接字串:
jdbc:sybase:Tds:127.0.0.1:4000/database?charset=utf8&jconnect_version=0
类似的,在SQL语句中使用字符N修饰的字串,使SQL分析器认为字串是Unicode编码的。
对于MySQL数据库,系统支持四个级别的字符集设置:
连接,数据库,表,字段
MySQL参考手册第9章有详细的讨论,但注意版本要求4.1.0以上,同时Windows
(nt,2k,xp) 的用户请注意 4.1.0 有个bug,你必须使用4.1.1才能正确使用Unicode。
在 SQL Server 和 Sybase 中都有N开头的字段类型,它们被设计用于国际化的字符
存储。在SQL Server中,比如NTEXT实际上就是用Unicode存储的的字段类型。
SQL-99规定了Unicode字符串统一使用 u 前缀,如 u"コンピュータ",但目前还没
有见哪个数据库系统支持这种语法。
附:几个字符集支持的测试例子 (需要测试用的源码可以向我要:
jljljjl@yahoo.com) 声明:
Connection c;
Statement s;
生成数据:
String lit1 = "的文本:中华人民共和国]";
String[] encs = new String[] {
"(default)",
"ISO-8859-1",
"cp850",
"gb2312",
"gbk",
"big5",
"UTF-16LE",
"UTF-16BE",
"UTF-8", };
String javaSrc = "[这是默认编码" + lit1;
byte[] rawdata;
s.executeUpdate("DELETE FROM StringTable");
for (int i = 0; i < encs.length; i++) {
String targetEncoding = encs[i];
javaSrc = "[这是" + targetEncoding + lit1;
String testTarget;
if (i == 0) {
rawdata = javaSrc.getBytes();
testTarget = new String(rawdata);
} else {
rawdata = javaSrc.getBytes(targetEncoding);
testTarget = new String(rawdata); }
System.out.println(testTarget);
String sql = ("INSERT INTO StringTable(charset,text) VALUES(" +
"'" + targetEncoding + "', N'" + testTarget + "')");
System.out.println(sql);
s.executeUpdate(sql); }
获取数据:
ResultSet rs = s.executeQuery("SELECT * FROM StringTable");
String charset;
String text;
while (rs.next()) {
charset = rs.getString("charset").trim();
text = rs.getString("text");
System.out.println(charset + ": [" + text + "]");
byte[] raws = text.getBytes();
String restore;
if ("(default)".equals(charset)) {
restore = new String(raws);
} else {
restore = new String(raws, charset); }
System.out.println(" --> [" + restore + "]"); }
典型测试结果:
SQL-Server, type = ntext
(default): [[这是(default)的文本:中华人民共和国]]
--> [[这是(default)的文本:中华人民共和国]]
ISO-8859-1: [[??ISO-8859-1???????????]]
--> [[??ISO-8859-1???????????]]
cp850: [[??cp850???????????]]
--> [[??cp850???????????]]
gb2312: [[这是gb2312的文本:中华人民共和国]]
--> [[这是gb2312的文本:中华人民共和国]]
gbk: [[这是gbk的文本:中华人民共和国]]
--> [[这是gbk的文本:中华人民共和国]]
big5: [[?琌big5ゅセい?チ㎝?]]
--> [[?是big5的文本:中?人民共和?]]
UTF-8: [[杩欐槸UTF-8鐨勬枃鏈細涓崕浜烘皯鍏卞拰鍥絔]
--> [[这是UTF-8的文本:中华人民共和国]]
SQL-Server, type = text
(default): [[这是(default)的文本:中华人民共和国]]
--> [[这是(default)的文本:中华人民共和国]]
ISO-8859-1: [[??ISO-8859-1???????????]]
--> [[??ISO-8859-1???????????]]
cp850: [[??cp850???????????]]
--> [[??cp850???????????]]
gb2312: [[这是gb2312的文本:中华人民共和国]]
--> [[这是gb2312的文本:中华人民共和国]]
gbk: [[这是gbk的文本:中华人民共和国]]
--> [[这是gbk的文本:中华人民共和国]]
big5: [[?琌big5ゅセい?チ㎝?]]
--> [[?是big5的文本:中?三民囝和?]]
UTF-8: [[杩欐槸UTF-8鐨勬枃鏈細涓崕浜烘皯鍏卞拰鍥絔]
--> [[这是UTF-8的文本:中华人民共和国]]
Sybase, type = char
(default): [[??(default)???????????]]
--> [[??(default)???????????]]
ISO-8859-1: [[??ISO-8859-1???????????]]
--> [[??ISO-8859-1???????????]]
cp850: [[??cp850???????????]]
--> [[??cp850???????????]]
gb2312: [[??gb2312???????????]]
--> [[??gb2312???????????]]
gbk: [[??gbk???????????]]
--> [[??gbk???????????]]
big5: [[??big5???????????]]
--> [[??big5???????????]]
UTF-16LE
--> [[?啦吀??????????乎?民共?]]
UTF-16BE:
--> [[??唀吀??????????乎?共吿??]
UTF-8: [[???UTF-8?????????????????]
--> [[???UTF-8?????????????????]
Sybase, type = nchar
(default): [[??(default)???????????]]
--> [[??(default)???????????]]
ISO-8859-1: [[??ISO-8859-1???????????]]
--> [[??ISO-8859-1???????????]]
cp850: [[??cp850???????????]]
--> [[??cp850???????????]]
gb2312: [[??gb2312???????????]]
--> [[??gb2312???????????]]
gbk: [[??gbk???????????]]
--> [[??gbk???????????]]
big5: [[??big5???????????]]
--> [[??big5???????????]]
UTF-16LE
--> [[?啦吀??????????乎?民共?]]
UTF-16BE:
--> [[??唀吀??????????乎?共吿??]
UTF-8: [[???UTF-8?????????????????]
--> [[???UTF-8?????????????????]
Sybase, type = char, charset=utf8
(default): [[这是(default)的文本:中华人民共和国]]
--> [[这是(default)的文本:中华人民共和国]]
ISO-8859-1: [[??ISO-8859-1???????????]]
--> [[??ISO-8859-1???????????]]
cp850: [[??cp850???????????]]
--> [[??cp850???????????]]
gb2312: [[这是gb2312的文本:中华人民共和国]]
--> [[这是gb2312的文本:中华人民共和国]]
gbk: [[这是gbk的文本:中华人民共和国]]
--> [[这是gbk的文本:中华人民共和国]]
big5: [[?琌big5ゅセい?チ㎝?]]
--> [[?是big5的文本:中?人民共和?]]
UTF-16LE: [[这是UTF-16LE的文本?中华人民共和国]]
UTF-16BE: [[这是UTF-16BE的文本?中华人民共和嘿]]
UTF-8: [[杩欐槸UTF-8鐨勬枃鏈細涓崕浜烘皯鍏卞拰鍥絔]
--> [[这是UTF-8的文本:中华人民共和国]]
Sybase, type = nchar, charset=utf8
(default): [[这是(default)的文本:中华人民共和国]]
--> [[这是(default)的文本:中华人民共和国]]
ISO-8859-1: [[??ISO-8859-1???????????]]
--> [[??ISO-8859-1???????????]]
cp850: [[??cp850???????????]]
--> [[??cp850???????????]]
gb2312: [[这是gb2312的文本:中华人民共和国]]
--> [[这是gb2312的文本:中华人民共和国]]
gbk: [[这是gbk的文本:中华人民共和国]]
--> [[这是gbk的文本:中华人民共和国]]
big5: [[?琌big5ゅセい?チ㎝?]]
--> [[?是big5的文本:中?人民共和?]]
UTF-16LE: --> [[这是UTF-16LE的文本?中华人民共和国]]
UTF-16BE: --> [[这是UTF-16BE的文本?中华人民共和嘿]]
UTF-8: [[杩欐槸UTF-8鐨勬枃鏈細涓崕浜烘皯鍏卞拰鍥絔]
--> [[这是UTF-8的文本:中华人民共和国]]
Sybase, type = char, charset=cp936
(default): [[这是(default)的文本:中华人民共和国]]
--> [[这是(default)的文本:中华人民共和国]]
ISO-8859-1: [[??ISO-8859-1???????????]]
--> [[??ISO-8859-1???????????]]
cp850: [[??cp850???????????]]
--> [[??cp850???????????]]
gb2312: [[这是gb2312的文本:中华人民共和国]]
--> [[这是gb2312的文本:中华人民共和国]]
gbk: [[这是gbk的文本:中华人民共和国]]
--> [[这是gbk的文本:中华人民共和国]]
big5: [[?琌big5ゅセい?チ㎝?]]
--> [[?是big5的文本:中?人民共和?]]
UTF-16LE: --> [[这是UTF-16LE的文本?中华人民共和国]]
UTF-16BE: --> [[这是UTF-16BE的文本?中华人民共和嘿]]
UTF-8: [[杩欐槸UTF-8鐨勬枃鏈細涓崕浜烘皯鍏卞拰鍥絔]
--> [[这是UTF-8的文本:中华人民共和国]]
Sybase, type = char, charset=eucgb
(default): [[这是(default)的文本:中华人民共和国]]
--> [[这是(default)的文本:中华人民共和国]]
ISO-8859-1: [[??ISO-8859-1???????????]]
--> [[??ISO-8859-1???????????]]
cp850: [[??cp850???????????]]
--> [[??cp850???????????]]
gb2312: [[这是gb2312的文本:中华人民共和国]]
--> [[这是gb2312的文本:中华人民共和国]]
bk: [[这是gbk的文本:中华人民共和国]]
--> [[这是gbk的文本:中华人民共和国]]
big5: [[??big5?ゅセ?い??チ???]]
--> [[??big5?文本?中??民???]]
UTF-16LE: --> [[?啦吀??????????乎?民共?]]
UTF-16BE: --> [[??唀吀??????????乎?共吿??]
UTF-8: [[杩??UTF-8??????涓??浜烘??卞???]
--> [[???UTF-8?????????人????????]
Sybase, type = nchar, charset=eucgb
(default): [[这是(default)的文本:中华人民共和国]]
--> [[这是(default)的文本:中华人民共和国]]
ISO-8859-1: [[??ISO-8859-1???????????]]
--> [[??ISO-8859-1???????????]]
p850: [[??cp850???????????]]
--> [[??cp850???????????]]
gb2312: [[这是gb2312的文本:中华人民共和国]]
--> [[这是gb2312的文本:中华人民共和国]]
gbk: [[这是gbk的文本:中华人民共和国]]
--> [[这是gbk的文本:中华人民共和国]]
big5: [[??big5?ゅセ?い??チ???]]
--> [[??big5?文本?中??民???]]
UTF-16LE: --> [[?啦吀??????????乎?民共?]]
UTF-16BE: --> [[??唀吀??????????乎?共吿??]
UTF-8: [[杩??UTF-8??????涓??浜烘??卞???]
--> [[???UTF-8?????????人????????]

 

 

--------------------------------------------------------------------

 

GB2312,GBK和UTF-8的区别

GBK包含全部中文字符, GBK的文字编码是双字节来表示的,即不论中、英文字符均使用双字节来表示,只不过为区分中文,将其最高位都定成1。
至于UTF-8编码则是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24位(三个字节)来编码。对于英文字符较多的论坛则用UTF-8节省空间。

GBK包含全部中文字符,
UTF-8则包含全世界所有国家需要用到的字符。
GBK是在国家标准GB2312基础上扩容后兼容GB2312的标准
UTF-8编码的文字可以在各国各种支持UTF8字符集的浏览器上显示。
比如,如果是UTF8编码,则在外国人的英文IE上也能显示中文,而无需他们下载IE的中文语言支持包。
对于英文比较多的论坛,使用GBK则每个字符占用2个字节,而使用UTF-8英文却只占一个字节。

分享到:
评论
1 楼 kayo 2008-08-02  
2.1. iso8859-1

属于单字节编码,最多能表示的字符范围是0-255,应用于英文系列。比如,字母'a'的编码为0x61=97。

很明显,iso8859-1编码表示的字符范围很窄,无法表示中文字符。但是,由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用iso8859-1编码来表示。而且在很多协议上,默认使用该编码。比如,虽然"中文"两个字不存在iso8859-1编码,以gb2312编码为例,应该是"d6d0 cec4"两个字符,使用iso8859-1编码的时候则将它拆开为4个字节来表示:"d6 d0 ce c4"(事实上,在进行存储的时候,也是以字节为单位处理的)。而如果是UTF编码,则是6个字节"e4 b8 ad e6 96 87"。很明显,这种表示方法还需要以另一种编码为基础。

2.2. GB2312/GBK

这就是汉子的国标码,专门用来表示汉字,是双字节编码,而英文字母和iso8859-1一致(兼容iso8859-1编码)。其中gbk编码能够用来同时表示繁体字和简体字,而gb2312只能表示简体字,gbk是兼容gb2312编码的。

2.3. unicode

这是最统一的编码,可以用来表示所有语言的字符,而且是定长双字节(也有四字节的)编码,包括英文字母在内。所以可以说它是不兼容iso8859 -1编码的,也不兼容任何编码。不过,相对于iso8859-1编码来说,uniocode编码只是在前面增加了一个0字节,比如字母'a'为"00 61"。

需要说明的是,定长编码便于计算机处理(注意GB2312/GBK不是定长编码),而unicode又可以用来表示所有字符,所以在很多软件内部是使用unicode编码来处理的,比如java。

2.4. UTF

考虑到unicode编码不兼容 iso8859-1编码,而且容易占用更多的空间:因为对于英文字母,unicode也需要两个字节来表示。所以unicode不便于传输和存储。因此而产生了utf编码,utf编码兼容iso8859-1编码,同时也可以用来表示所有语言的字符,不过,utf编码是不定长编码,每一个字符的长度从1-6 个字节不等。另外,utf编码自带简单的校验功能。一般来讲,英文字母都是用一个字节表示,而汉字使用三个字节。

注意,虽然说utf是为了使用更少的空间而使用的,但那只是相对于unicode编码来说,如果已经知道是汉字,则使用GB2312/GBK无疑是最节省的。不过另一方面,值得说明的是,虽然utf编码对汉字使用3个字节,但即使对于汉字网页,utf编码也会比unicode编码节省,因为网页中包含了很多的英文字符。

相关推荐

    Oracle11g体系结构深入剖析和运维管理(五)

    资源名称:Oracle 11g体系结构深入剖析和运维管理(五)资源目录:【】37_深入剖析事务槽及Oracle多种提交方式【】38_OracleIMU及RedoPrivateStrands技术【】39_读一致性(ORA-01555错误机制分析)及Undo表空间大小设置...

    .Net框架联合Oracle字符集问题研究.pdf

    《.Net框架联合Oracle字符集问题研究》这篇文章深入探讨了在使用.Net框架开发应用程序与Oracle数据库结合时遇到的字符集问题,特别是在处理汉字和生僻字时出现的乱码现象。作者莫佩宏和吴紫薇通过对问题的全方位剖析...

    Redis从入门到精通(深入剖析)【55集完整资料】20-redis-redis中关于字符串类型数据的操作命令1.avi

    Redis从入门到精通高清,迅雷播放器组件可顺利播放

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part2

    21.1.1 常用字符集 610 21.1.2 对乱码产生过程的分析 612 21.2 中文乱码问题的解决方案 614 21.3 使用过滤器解决中文问题 616 21.4 让tomcat支持中文文件名 620 21.5 国际化与本地化 621 21.5.1 locale 621.. ...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part3

    21.1.1 常用字符集 610 21.1.2 对乱码产生过程的分析 612 21.2 中文乱码问题的解决方案 614 21.3 使用过滤器解决中文问题 616 21.4 让tomcat支持中文文件名 620 21.5 国际化与本地化 621 21.5.1 locale 621.. ...

    深入剖析printf函数

    通过上述对printf函数的深入剖析,我们可以发现它不仅仅是一个简单的输出函数,背后涉及到C语言标准库的封装、系统调用机制、汇编语言实现等复杂的计算机科学知识。了解这些知识点,有助于我们更深入地理解程序的...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part4

    21.1.1 常用字符集 610 21.1.2 对乱码产生过程的分析 612 21.2 中文乱码问题的解决方案 614 21.3 使用过滤器解决中文问题 616 21.4 让tomcat支持中文文件名 620 21.5 国际化与本地化 621 21.5.1 locale 621.. ...

    深入剖析JSP和Servlet对中文的处理

    ### 深入剖析JSP和Servlet对中文的处理 #### 一、引言 在全球化的今天,软件和Web应用程序必须能够支持多种语言环境,尤其是像中文这样的复杂语言。Java作为一种广泛使用的编程语言,提供了丰富的工具和技术来处理...

    深入剖析 MongoDB 架构

    本文将深入剖析 MongoDB 的架构,帮助你更好地理解其工作原理。 首先,我们来了解一下 MongoDB 的基本架构。MongoDB 采用的是主从复制(Replica Sets)和分片(Sharding)两种方式来实现高可用性和水平扩展。主从...

    深入剖析midp 2.0

    深入剖析MIDP 2.0:理解CLDC与MIDP工具类别的核心价值 在深入了解MIDP 2.0(Mobile Information Device Profile)及其底层架构CLDC(Connected Limited Device Configuration)的过程中,我们首先需要关注的是MIDP...

    深入剖析Java 编程中的中文问题及建议最优解决方法

    3. 数据库操作的乱码:与数据库交互时,如MySQL或Oracle,需要确保数据库连接的字符集设置与Java应用程序保持一致。这通常在数据库连接URL、JDBC驱动配置或数据库服务器配置中完成。 4. 字符串编码与解码:使用`...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part5

    21.1.1 常用字符集 610 21.1.2 对乱码产生过程的分析 612 21.2 中文乱码问题的解决方案 614 21.3 使用过滤器解决中文问题 616 21.4 让tomcat支持中文文件名 620 21.5 国际化与本地化 621 21.5.1 locale 621.. ...

    关于Lucene的词典FST深入剖析-申艳超1

    《关于Lucene的词典FST深入剖析》这篇文章是由申艳超撰写的,主要探讨了Apache Lucene这个全文搜索引擎库中的一个关键数据结构——有限状态转换器(Finite State Transducer,简称FST)。FST在Lucene中被用于构建和...

    Redis从入门到精通(深入剖析)【55集完整资料】21-redis-redis中关于字符串类型数据的操作命令2.avi

    Redis从入门到精通高清,迅雷播放器组件可顺利播放

    atl开发技术深入解析_part2

    总之,《ATL开发技术深入解析_part2》深入剖析了ATL框架下COM数据类型的应用,特别强调了字符串管理和智能类型的重要性。通过对BSTR、VARIANT和接口指针的封装,ATL不仅简化了开发流程,还提升了组件的性能和可靠性...

    oracle 学习笔记

    Oracle数据库是一类关系型数据库管理系统(RDBMS),由美国Oracle公司开发。...学习Oracle数据库和SQL知识是一个逐步深入的过程,从最基础的数据库概念到高级的事务管理,每个知识点都需要认真掌握和实践。

    深入剖析Java编程中的中文问题及建议最优解决方法.pdf

    7. 对于数据库操作,确保JDBC连接URL中包含了适当的字符集,如`jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8`。 8. 使用第三方库:如Apache Commons Lang的`StringUtils`或Google的...

    ASP.NET 2.0深度剖析范例集.

    这个深度剖析范例集旨在帮助开发者深入理解ASP.NET 2.0的核心概念和技术,通过实例学习来提升开发效率和应用性能。 1. **页面生命周期**:ASP.NET 2.0中的每个Web页面都有一个从加载到卸载的生命周期,包括初始化、...

    web前端黑客技术揭秘

    主要包含Web前端安全的跨站脚本(XSS)、跨站请求伪造(CSRF)、界面操作劫持这三大类,涉及的知识点涵盖信任与信任关系、Cookie安全、Flash安全、DOM渲染、字符集、跨域、原生态攻击、高级钓鱼、蠕虫思想等,这些都...

Global site tag (gtag.js) - Google Analytics