paulxie
作者paulxie·2012-06-01 15:25
数据库管理员·CMBC

DB2+AIX 字符集问题

字数 8073阅读 11540评论 1赞 1
工作需要,了解了一下字符集和字符编码的相关知识,记录备查,不断更新。。。

字符,字符集与字符编码:
起步知识是知道字符,字符集和字符编码的区别与联系。
字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。
字符集顾名思义就是字符的集合。另外,字符集常常和一种具体的语言文字对应起来,该文字中的所有字符或者大部分常用字符就构成了该文字的字符集,比如英文字符集。 一组有共同特征的字符也可以组成字符集,比如繁体汉字字符集、日文汉字字符集。 字符集的子集也是字符集。
字符编码(Encoding)是字符与二进制码的对应关系。计算机为处理字符需要把字符转换为二进制码,显示的时候再转为字符。制定编码首先要确定字符集,并将字符集内的字符排序,然后和二进制数字对应起来。根据字符集内字符的多少,会确定用几个字节来编码。 每种编码都限定了一个明确的字符集合,叫做被编码过的字符集(Coded Character Set),这是字符集的另外一个含义。通常所说的字符集大多是这个含义。 因此有时候会混淆字符集和字符编码的概念。

常用的字符集和字符编码:
ASCII字符集:主要包括控制字符(回车键、退格、换行键等);可显示字符(英文大小写字符、阿拉伯数字和西文符号)。
ASCII字符编码:ASCII字符集有7bit,只能表示128个字符;为表示更过的欧洲常用字符,产生了ASCII扩展字符集(EASCII),包含8bit表示256个字符
ASCII的最大缺点是只能显示26个基本拉丁字母、阿拉伯数目字和英式标点符号,因此只能用于显示现代美国英语(而且在处理英语当中的外来词如naïve、café、élite等等时,所有重音符号都不得不去掉,即使这样做会违反拼写规则)。而EASCII虽然解决了部份西欧语言的显示问题,但对更多其他语言依然无能为力。

ISO 8859-1:
ISO 8859,全称ISO/IEC 8859,是国际标准化组织(ISO)及国际电工委员会(IEC)联合制定的一系列8位字符集的标准,现时定义了15个字符集。
ASCII收录了空格及94个“可印刷字符”,足以给英语使用。
但是,其他使用拉丁字母的语言(主要是欧洲国家的语言),都有一定数量的变音字母,故可以使用ASCII及控制字符以外的区域来储存及表示。
除了使用拉丁字母的语言外,使用西里尔字母的东欧语言、希腊语、泰语、现代阿拉伯语、希伯来语等,都可以使用这个形式来储存及表示。
    * ISO 8859-1 (Latin-1) - 西欧语言
    * ISO 8859-2 (Latin-2) - 中欧语言
    * ISO 8859-3 (Latin-3) - 南欧语言。世界语也可用此字符集显示。
    * ISO 8859-4 (Latin-4) - 北欧语言
    * ISO 8859-5 (Cyrillic) - 斯拉夫语言
    * ISO 8859-6 (Arabic) - 阿拉伯语
    * ISO 8859-7 (Greek) - 希腊语
    * ISO 8859-8 (Hebrew) - 希伯来语(视觉顺序)
    * ISO 8859-8-I - 希伯来语(逻辑顺序)
    * ISO 8859-9 (Latin-5 或 Turkish) - 它把Latin-1的冰岛语字母换走,加入土耳其语字母。
    * ISO 8859-10 (Latin-6 或 Nordic) - 北日耳曼语支,用来代替Latin-4。
    * ISO 8859-11 (Thai) - 泰语,从泰国的 TIS620 标准字集演化而来。
    * ISO 8859-13 (Latin-7 或 Baltic Rim) - 波罗的语族
    * ISO 8859-14 (Latin-8 或 Celtic) - 凯尔特语族
    * ISO 8859-15 (Latin-9) - 西欧语言,加入Latin-1欠缺的法语及芬兰语重音字母,以及欧元符号。
    * ISO 8859-16 (Latin-10) - 东南欧语言。主要供罗马尼亚语使用,并加入欧元符号。
很明显,iso8859-1编码表示的字符范围很窄,无法表示中文字符。
但是,由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用iso8859-1编码来表示。
GB2312GB2312-80又称GB0)字符集:
收录了6763个汉字。2字节编码,小于127的编码与ASCII相同,两个字节表示一个汉字。在这些编码里,还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了(这就是全角与半角)
GBK字符集(编码):
微软利用GB 2312-80未使用的编码空间,收录GB 13000.1-93全部字符制定了GBK编码。GBK字集是简繁字集,包括了GB字集、BIG5字集和一些符号,共包括21003个字符。
GB 18030字符集(编码):
是国家制定的一个强制性大字集标准,它的推出使汉字集有了一个“大一统”的标准。 共收录汉字70244个。与UTF-8相同,采用多字节编码,每个字可以由1个、2个或4个字节组成。
BIG5(又称为大五码五大码):
Big5码是一套双字节编码字符集。是台湾繁体字集,共包括国标繁体汉字13053个。
Unicode(统一码、万国码、单一码):
它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
Unicode的编码系统比较特殊,分为编码方式和实现方式两个层次。
编码方式:
Unicode最多可以容纳1114112个字符,或者说有1114112个码位,码位就是可以分配给字符的数字。
实现方式:
UTF-8,UTF-16,UTF-32都是将数字转换到程序数据的编码方案。举个例子如下:
在Unicode中:汉字“字”对应的数字是23383。在Unicode中,我们有很多方式将数字23383表示成程序中的数据,包括:UTF-8、UTF-16、UTF-32。UTF是“UCS Transformation Format”的缩写,可以翻译成Unicode字符集转换格式,即怎样将Unicode定义的数字转换成程序数据。例如,“汉字”对应的数字是0x6c49和0x5b57,
而编码的程序数据是:   

BYTE data_utf8[] = {0xE6, 0xB1, 0x89, 0xE5, 0xAD, 0x97}; // UTF-8编码   
WORD data_utf16[] = {0x6c49, 0x5b57}; // UTF-16编码   
DWORD data_utf32[] = {0x6c49, 0x5b57}; // UTF-32编码   

这里用BYTE、WORD、DWORD分别表示无符号8位整数,无符号16位整数和无符号32 位整数。UTF-8、UTF-16、UTF-32分别以BYTE、WORD、DWORD作为编码单位。“汉字”的UTF-8编码需要6个字节。“汉字”的 UTF-16编码需要两个WORD,大小是4个字节。“汉字”的UTF-32编码需要两个DWORD,大小是8个字节。根据字节序的不同,UTF-16可 以被实现为UTF-16LE或UTF-16BE,UTF-32可以被实现为UTF-32LE或UTF-32BE。下面介绍UTF-8、UTF-16、 UTF-32、字节序和BOM。

为什么乱码:
乱码是个老问题,从上面我们知道,字符在保存时的编码格式如果和要显示的编码格式不一样的话,就会出现乱码问题。
我们的Web系统,从底层数据库编码、Web应用程序编码到HTML页面编码,如果有一项不一致的话,就会出现乱码。
所以,解决乱码问题说难也难说简单也简单,关键是让交互系统之间编码一致。

使用Unicode编码的原因:

基本上,计算机只是处理数字。它们指定一个数字,来储存字母或其他字符。在创造Unicode之前,有数百种指定这些数字的编码系统。没有一个编码可以包 含足够的字符:例如,单单欧州共同体就需要好几种不同的编码来包括所有的语言。即使是单一种语言,例如英语,也没有哪一个编码可以适用于所有的字母,标点 符号,和常用的技术符号。这些编码系统也会互相冲突。也就是说,两种编码可能使用相同的数字代表两个不同的字符,或使用不同的数字代表相同的字符。任何一 台特定的计算机(特别是服务器)都需要支持许多不同的编码,但是,不论什么时候数据通过不同的编码或平台之间,那些数据总会有损坏的危险。





AIX locale命令相关:
查看已安装的语言包:#locale -a
查看当前的设置:#locale
修改设置:#export LC_ALL=ZH_CN.UTF-8
locale的书写格式:[语言[_地域][.字符集] [@修正值]     语言(Language), 地域 (Territory) 和字符集(Codeset)
下面举几个例子:  
1、我说中文,身处中华人民共和国,使用国标2312字符集来表达字符。 zh_CN.GB2312=中文_中华人民共和国+国标2312字符集。  
2、我说中文,身处中华人民共和国,使用国标18030字符集来表达字符。 zh_CN.GB18030=中文_中华人民共和国+国标18030字符集。  
3、我说中文,身处中华人民共和国台湾省,使用国标Big5字符集来表达字符。 zh_TW.BIG5=中文_台湾.大五码字符集  
4、我说英文,身处大不列颠,使用ISO-8859-1字符集来表达字符。 en_GB.ISO-8859-1=英文_大不列颠.ISO-8859-1字符集  
5、我说德语,身处德国,使用UTF-8字符集,习惯了欧洲风格。 de_DE.UTF-8@euro=德语_德国.UTF-8字符集@按照欧洲习惯加以修正  
注意不是de_DE@euro.UTF-8
locale分类:
locale把按照所涉及到的文化传统的各个方面分成几类,包括:
LC_CTYPE-语言符号及其分类
LC_NUMERIC-数字
LC_COLLATE-比较和排序习惯
LC_TIME-时间显示格式
LC_MONETARY-货币单位
LC_MESSAGES-信息主要是提示信息,错误信息, 状态信息, 标题, 标签, 按钮和菜单等
其中,与中文输入关系最密切的就是 LC_CTYPE, LC_CTYPE 规定了系统内有效的字符以及这些字符的分类,诸如什么是大写字母,小写字母,大小写转换,标点符号、可打印字符和其他的字符属性等方面。
设定locale:
设定locale就是设定locale的分类属性,即 LC_*。除了这几个个变量可以设定以外,为了简便起见,还有两个变量:LC_ALL和LANG。它们之间有一个优先级的关系: LC_ALL>LC_*>LANG 可以这么说,LC_ALL是最上级设定或者强制设定,而LANG是默认设定值。 1、如果你设定了LC_ALL=zh_CN.UTF-8,那么不管LC_*和LANG设定成什么值,它们都会被强制服从LC_ALL的设定,成为 zh_CN.UTF-8。 2、假如你设定了LANG=zh_CN.UTF-8,而其他的LC_*=en_US.UTF-8,并且没有设定LC_ALL的话,那么系统的locale 设定以LC_*=en_US.UTF-8。 3、假如你设定了LANG=zh_CN.UTF-8,而其他的LC_*,和LC_ALL均未设定的话,系统会将LC_*设定成默认值,也就是LANG的值 zh_CN.UTF-8 。 4、假如你设定了LANG=zh_CN.UTF-8,而其他的LC_CTYPE=en_US.UTF-8,其他的LC_*均未设定的话, 那么系统的locale设定将是:LC_CTYPE=en_US.UTF-8,其余的 LC_COLLATE,LC_MESSAGES等等均会采用默认值,也就是LANG的值,也就是LC_COLLATE=LC_MESSAGES=…… =LANG=zh_CN.UTF-8。  
所以,locale是这样设定的: 1、如果你需要一个纯中文的系统的话,设定LC_ALL= zh_CN.XXXX,或者LANG= zh_CN.XXXX都可以,当然你可以两个都设定,但正如上面所讲,LC_ALL的值将覆盖所有其他的locale设定,不要作无用功。 2、如果你只想要一个可以输入中文的环境,而保持菜单、标题,系统信息等等为英文界面,那么只需要设定LC_CTYPE=zh_CN.XXXX,LANG = en_US.XXXX就可以了。这样LC_CTYPE=zh_CN.XXXX,而LC_COLLATE=LC_MESSAGES=……= LANG=en_US.XXXX。 3、假如你高兴的话,可以把LC_*一一设定成你需要的值,打造一个古灵精怪的系统: LC_CTYPE=zh_CN.GBK/GBK(使用中文编码内码GBK字符集); LC_NUMERIC=en_GB.ISO-8859-1(使用大不列颠的数字系统) .估计没人这么干吧。 4、假如你什么也不做的话,也就是LC_ALL,LANG和LC_*均不指定特定值的话,系统将采用POSIX作为lcoale,也就是C locale。


AIX中文件编码的转换:
AIX下,进行编码转换,可以使用命令iconv实现,不过我还没找到在AIX查看文件编码的方法,继续学习... ...





好,基础差不多了,现在回到DB2中来说说字符问题:
CODEPAGE概念:
计算机处理文本时,把一门语言中每个字符都赋以特定的值,这种字符与数值的对照表就叫 codepage( 代码页 ) 。例如 ASCII 就是把英文字母表和一些控制字符映射到一些特定的数值上去。

DB2使用代码页(codepage)来指定字符集.换句话说,DB2中的代码页是从操作系统中的字符集映射而来的.比如代码页1208即UTF-8编码的Unicode字符集;819对应ISO8859-1;1200对应16 位 Unicode;1386对应GBK字符集.其他对应关系可以查询信息中心(http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=/com.ibm.db2.luw.admin.nls.doc/doc/r0004565.html)
代码页是字符"代码"和数据库中它的二进制编码(表示)间的映射.因此,代码页和所有的DB2字符数据类型(CHAR,VARCHAR,CLOB,DBCLOB)相关.
一个数据库只能是用单一代码页,在创建数据库时指定(CREATE DATABASE TESTDB1 USING CODESET UTF-8 TERRITORY CN)其中CODESET就指定了数据库的codepage.
注意:二进制数据,如FOR BIT DATA列和BLOB列和数据库代码页无关,不许要字符转换.
默认的情况下,数据库的排列顺序(collating sequence)根据CREATE DATABASE命令所使用的代码集定义。如果指定COLLATE USING SYSTEM选项,则数据值将按照为数据库指定的TERRITORY进行比较。如果使用COLLATE USING IDENTITY选项,则所有的值都以二进制的形式逐字节地进行比较。

在DB2数据库中,与字符集相关的问题主要有三个层次的字符集的设置,其中system级别(操作系统级别)和instance级别(注册表变量)的字符集可以根据需求进行修改, 而db级别的数据集则必须在建库时确定


数据导入,导出,装载操作相关的代码页:
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=/com.ibm.db2.luw.admin.nls.doc/doc/r0004565.html包含了代码页和字符集的对应关系.
在表中,每个 codepage 都有相对应的组,地域代码,代码集等。如果两个 codepage 属于同一个组,则它们可以互相转换,否则不可以互相转换。值得注意的是单字节(S)组可以转换成中性(N)组,双字节(D)组也可以转换为中性(N)组。 但是 N 组不一定能转成 S 组,N 组也不一定成转成 D 组。

在使用export导出数据的时候,可以使用modified by的选项codepage指定导出文件的代码页,如:
$db2 "export to data819.del of del modified by codepage=819 select * from tab1"

在import和load数据时,也可以使用modified by的选项codepage通知DB2被导入文件的代码页,如:
$db2 load from data1208.del of del modified by codepage=1208 replace into t1
$db2 import from data1208.del of del modified by codepage=1208 replace into t1

注意:
1.LOAD与IMPORT代码页转换方式不同:
缺省情况下,LOAD 认为输入文件是用数据库代码页编码的,直接将文件转化为数据库 codepage 编码。如果输入文件不是以数据库 codepage 编码的,可以通过 codepage 修饰符来导入正确文件。而缺省情况下 DB2 IMPORT 实用程序认为输入文件中的数据是用当前系统的代码页(这里指的是实例级代码页,及db2set设置的db2codepage)编码的。当将数据文件导入到数据库时,DB2 会自动将数据文件从当前系统代码页转换成数据库代码页。如果输入文件不是当前系统的代码页编码的。也可以通过 codepage 修饰符来轻松导入正确文件。
2.ixf 格式在导出的文件里面已经包括了文件的codepage(IXF模式在导出的时候可以指定CODEPAGE),因此导入的时候db2会自己检测到相应的 codepage然后使用正确的方式导入,因此对于IXF格式,一般不会出现编码问,因为会发生自动编码转换。对于DEL格式,当在不同系统间 export/import/load数据时,由于数据的编码不同,可能会遇到汉字乱码问题

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

1

添加新评论1 条评论

agfyingagfying网络工程师易家电子
2013-12-11 08:38
学习了
Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

X社区推广