解决Informix中文乱码问题
一、Informix中文乱码问题
可能很多朋友已经发现,使用Informix CSDK 2.7以上版本连接Informix服务器时,客户端得到的中文字符是乱码。我研究了一些Informix资料,发现这个问题的原因在于这些Informix数据库都没有使用中文LOCALE如GB18030,而使用了Informix默认的en_US.819。
Informix有多语言支持功能The Global Language Support (GLS)。GLS涉及到以下三个概念:
- LOCALE:即语言、区域、时间、书写方向等的总称,分为服务器端的DBLOCALE和客户端的CLIENTLOCALE;
- code-set files:字符集文件;
- code-set conversion files:字符集转换文件。
Informix服务器在创建数据库时应该指定符合所在区域文字习惯的DBLOCALE。如果不指定,则会采用默认的en_US.8859-1,美国英语及ISO 8859-1字符集。
Informix的客户端同样也需要指定合适的CLIENTLOCALE。当DBLOCALE或CLIENTLOCALE与实际存储的文字不符时,就会出现乱码。
有许多从上个世纪就开始使用Informix数据库的国内用户并不清楚GLS的作用,在初建数据库时都采用了默认的LOCALE。然而在早期(Informix CSDK 2.7版以前)Informix支持“GIGO”(垃圾入垃圾出)的策略,默认的LOCALE下仍可以处理中文,所以问题并没有暴露。Informix CSDK2.7以上版本后不再继续支持GIGO,字符串一律按照配置的LOCALE解释,当中文字符使用en_US.8859-1代码集解释时,就出现了乱码。
以下程序演示了一个字符串被GB编码存入数据库,再从数据库中取出后被8859-1解码变成乱码的过程。
//解决Informix乱码
private void informixEncoder(string text)
{
//ISO 8859-1编码器
Encoding Encoder_ISO8859 = Encoding.GetEncoding("ISO-8859-1");
//GB18030编解码器
Encoding Encoder_GB18030 = Encoding.GetEncoding("GB18030");
//编码后的字节流缓冲区
byte[] buffer;
try
{
//text是从Informix数据库取出的中文字符串,直接显示为乱码
//将原始字符按GB编码
buffer =Encoder_GB18030.GetBytes(text);
//显示字节流内容
txtEncoding.Clear();
foreach(byte item inbuffer)
{
txtEncoding.AppendText(item.ToString("X")+ " ");
}
//再以ISO 8859-1解码,显示正常
txtString8859.Text =Encoder_ISO8859.GetString(buffer);
//以GB解码,显示为乱码
txtStringGB.Text =Encoder_GB18030.GetString(buffer);
}
catch(Exception ex)
{
}
}
以下是程序运行的结果:
原始字符“Informix 中文乱码问题”经过终端软件的GB编码后,变成了“49 6E 66 6F 72 6D 69 78 20 D6 D0 CE C4 C2 D2 C2 EB CE CA CC E2”字节流,被Informix SERVER以8859-1的名义存入了数据库。用户读取数据时,数据库以8859-1进行解码,变成了“Informix ÖÐÎÄÂÒÂëÎÊÌâ”。
进一步测试说明,如果把这些字节流强行按GB解码,则得到了正确的结果。由此可见,从ISO 8859-1到GB的转换具有可行性。
二、DBHelper2的代码转换功能
DBHelper2已内置了以上的代码转换功能,要解决Informix中文乱码问题,仅仅需要在数据库连接串中配置一个选项:
ConvertEncoding=true
使用DBHelper2进行转码只是一个权宜之计,最好的做法当然是合理配置Informix,使用正确的DBLOCALE和CLIENTLOCALE。如果LOCALE与实际语言不匹配,不仅仅只是一个乱码的问题,更会涉及到对字符的排序、检索等字符相关计算的错误。