中文乱码问题分析及解决

C#访问MySQL数据库时中文乱码问题分析及解决 - 使用MySQL保存中文数据时,经常会遇到乱码问题。产生乱码的原因很多,在笔者以为对MySQL的字符集处理已经很有了解的时候,使用C#编程时,竟再一次遇到了乱码。联想到前几天一位同事在使用JDBC访问MySQL时遇到的中文乱码问题,决定对MySQL中文乱码问题的产生场景进行一次总结。 一、错误读出 现象:一个已经存在数据的MySQL数据库,该数据库的数据用系统中其它软件、网页查看均正常,使用MySQLcc之类的客户端查看也正常,可是在新写的网页中总是显示乱码。 分析:其它系统都可以正常查看数据,说明数据本身是没有问题的。在网页中显示乱码,一定是网页的编码字符集和获取到的数据的编码字符集不一至。比如数据库的字符集是UTF8的,而网页的字符集是gb2312的,那么网页就会把UTF8编码的字体串当作gb2312的来处理,结果产生乱码。 解决办法:在连接数据库时,设定连接字符集,使连接字符集和当前网页或客户端程序使用的字符集一致。可以使用MySQL的Set Names指令设定连接字符集。假设网页的字体集为gb2312。在连接MySQL后,在连接上执行如下SQL语句: Set Names ‘gb2312’ 在以后所有这个连接上的查询,MySQL都会自动把数据库中的数据转换成gb2312编码格式传过来。 二、错误写入 现象:一个网页或程序向一个MySQL数据库中写数据,写完后,这个网页或程序自己可以正常读取数据,而从其它客户端或网页中读取数据都是乱码。 分析:其它的正常的客户端出现乱码,说明数据库中的字符编码不对。写数据的那个网页能正常读取,是因为写和读都用了错误的编码格式,将错就错,反而能读出正确的数据了。比如数据库中设定的字符集为UTF8,而网页使用gb2312编码执行了插入数据的SQL,那么MySQL就会把这些gb2312的编码当成是UTF8的编码写进数据库。当其它客户端访问数据时,会按系统的设定,以UTF8 格式读取数据,而数据其实是使用gb2312编码的,结果就出现了乱码。只有写数据的那个网页会把这些数据当成gb2312的,也只有那个网页能正常显示数据。 解决办法:同第一条,即:使用Set Names指令设定连接字符集。 在设定了连接字符体的连接上执行数据操作,所有的数据都将被MySQL自动、正确地转换为数据库中设定的编码格式保存。 通过以上两点,我们可以看到,只要在连接MySQL时,正确地设定了字符集,无论数据库本身是使用什么格式编码的,都能得到正确的结果。也许有人会以为写数据时设定的字符集必需和读数据时一致,事实上完全没有必要。程序所要做的只是告诉 MySQL,目前操作MySQL使用的是什么字符集即可。因为MySQL会自动完成如下的转换工作: 写数据库时用的字符集-->存诸数据的字符集-->读取数据的字符集。 笔者以为MySQL对多语言字符集的处理是非常优秀的,并且每次建立到MySQL的连接都会立刻使用Set Names设定字符集,然而最近还是出现了一回乱码,如下面所述。 三、无知的程序包 现象:使用C#编程,使用MySQL提供的连接程序库包访问数据库,使用 MySqlConnection类连接数据库,连接之后立刻调用Set Names设定连接字符串,然后使用MySqlCommand类执行SQL,并使用MySqlDataReader读取数查询结果。然而,当我调用 MySqlDataReader的成员方法GetString获取数据的时候,发现得到的全是乱码。百思不得其解。 分析:经仔细检查,确信问题没有出在MySQL连接上面,这时我想到了C#中对 string类型的处理。在C#中字符串和C/C++中有很大不同。在C/C++中一个字符就是一个字节,而在C#中,按不同的编码格式,一个字符也可以是多个字节的。比如”啊”就是一个字符,如果一个字符串s=”啊”; 那么s的Length属性为1,而不是C/C++中的2。我想MySQL程序包也许并不知道连接上传过来的字符是什么编码的,它因为无知,所以只是按单字节字符把这些数据组织成一个string,这个生成的string就是我得到的乱码。事实上也的确是这样。 解决办法:把这些数据重新组织起来,然后使用正确的编码方法重新生成string。C#中System.Text包内的Encoding类提供了字符集的编/解码方法。 1)首先还是设定连接字符集,以确认收到的字符的编码方式。 2)把GetString得到的字符串转换到byte数组中。 3)使用Systec.Text.Encoding包中相应字符集的解码方法GetString得到新的字符串。 为了通用性,我们使用System.Text.Encoding的默认字符集。连接数据库时,设置数据库连接字符集使用的SQL指令strSetCharset为如下值: string strSetCharset = “Set Names ” + System. Text. Encoding .Default. HeaderName; 在获取数据时,使用下面的函数得到真正的字符串: private string DBStringToNormal(string dbStr) { byte[] str = new byte[dbStr.Length]; for (int i = 0; i < dbStr.Length; ++i) str[i] = (byte)(dbStr[i]); return System.Text.Encoding.Default.GetString(str, 0, dbStr.Length); }

 

*****************************************************************************************

Unicode 编码正逐渐成为多语言支持的最通用解决方案。采用 Unicode 编码的中文网页能在各种平台、各种类的浏览器上都得到很好的兼容。utf-8 是 Unicode 的一种存储/交换实现方式。对于不同数值范围的 Unicode 码,它采用变长的方式来编码:所有 ASCII 字符占用1个字节,大于 0x7f 的则占用2到4字节不等。可以看出,所有 ASCII 文件直接兼容 utf-8。另外,对于网页源代码这样 ASCII 字符占内容很大部分的文件来说,它通常比其他 Unicode 存储/交换格式(如utf-16,utf-32等)更节省空间。因此,utf-8 格式已在网站设计中广泛的使用。

但是,在 asp.net 中文网页中使用 utf-8 编码时,稍不小心就会造成中文乱码,令人头疼。对于这个问题,网上很多地方建议:在必要的地方仍使用 GB2312 编码。这样显然不是一个彻底的解决方案。本文讨论了如何如何在 asp.net 网站中完全使用 utf-8 编码。

在 Visual Studio 2005 中新建一个 asp.net 站点。在 web.config 文件中设置站点使用 utf-8 编码:

<?xml version="1.0"?>
...
<configuration>
    <system.web>
        <globalization fileEncoding="utf-8" />
    </system.web>
<configuration>
...

这样一来,VS 可以在一定程度上实现对 utf-8 的自动化支持,但不是很完善。经常还是会有乱码问题。下面的讨论在即使没有设置站点编码的情况下依然能有效解决中文乱码问题。

创建一个 asp.net 页面,并编写代码如下:

<%--sample.aspx--%>

<%@ Page Language="C#" AutoEventWireup="true"
    CodeFile="sample.aspx.cs" Inherits="sample" %>

<!DOCTYPE html PUBLIC 
    "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>测试</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:RadioButtonList ID="RadioButtonList1" runat="server">
            <asp:ListItem>旧日重来</asp:ListItem>
            <asp:ListItem>http://live.aulddays.com</asp:ListItem>
        </asp:RadioButtonList>
        <asp:Button ID="Button1" runat="server" Text="Submit"
        OnClick="Button1_Click" />
        <br />
        <asp:Label ID="Label1" runat="server"></asp:Label>

    </form>
</body>
</html>

Visual Studio 2005 创建的页面默认还是 GB2312 编码,下一步将网页转换为 utf-8 编码。这里推荐使用 Microsoft Expression Web 工具。这个软件的前身就是大名鼎鼎的 Frontpage。在更新为 Expresson Web 之后,它的功能又有了很大的增强,例如对 css 的加强支持、对 asp.net 控件甚至是 master page 的完美支持。因此可以说它是和 Visual Studio 2005 配合使用,编辑 asp.net 网页的首选工具。

在 Expression Web 里打开刚才创建的 sample.aspx,在 Design 视图里右键选 Page Properties,在 Language 标签里将 Save the document as 设置为 Unicode (UTF-8),确定,保存。这样Expression Web 会自动在源文件里加上文件说明编码的 <meta> 标签,并且将硬盘上保存的文件自动转换为 utf-8 格式。

再在 VS 中打开,居然就产生了乱码:

VS 2005 utf-8 乱码

这是由于 VS 里默认不检测 utf-8 编码,仍然按照 GB2312 的方式来解释这个文件。解决的方法有两个。一是在 VS 的 tools -> Options 菜单里打开 utf-8 强制检查:

VS 2005 utf-8 检测

二是为网页源代码加上 BOM (Byte-Order Mark) 标记,作为 Unicode 编码方式的签名(推荐使用,因为这样可以保证在任何时候都能正确的检测文件编码)。用 Ultraedit 打开刚才的 aspx 文件,点击 File -> Save as,在保存对话框中 Format 下拉框里选择 UTF-8,以原始文件名覆盖保存即可。此时,在16进制编辑模式下查看可以看到文件已经被加上了3个字节的 BOM 标记:

utf-8 BOM 标记

当然,在 VS 的另存为对话框中点击 Save 按钮右边的下拉菜单,并以 UTF-8 with signature 方式保存也可以达到相同效果。

这样,中文的 asp.net 网页就已经以 utf-8 方式保存并可以正常浏览了。下面为该网页编写按钮相应代码:

using System;

public partial class sample : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text = "您选择的是:" + 
            RadioButtonList1.SelectedValue;
    }
}

运行网页,点击 Submit,再次出现乱码!

运行乱码

更诡异的是,如果在 VS 的调试器里看的话都是好的。查阅相关资料可以发现如下线索:asp.net 的源代码编译之后的编码方式是和源文件本身的编码方式相同。因此,为了让源代码里的字符串也可以正常显示和处理,需要把源文件的存储方式也改成 utf-8,这次用 VS 或 UltraEdit 直接另存为 utf-8 格式即可,记得顺便选上带 BOM 的保存。这样,网页的显示就完全正常了。

总结

如果在中文 asp.net 中使用 utf-8 编码,需要做到以下几点:

  1. html 代码中要加入定义文件编码的 <meta> 标记
  2. .aspx 文件 和对应的源代码文件的物理保存格式需要转化为 utf-8
  3. 建议在代码文件加入 BOM 头标记,明确指出其物理格式
  4. 在web.config文件中指明站点编码,可以在一定程度上避免中文乱码

*****************************************************************************************

.net中中文乱码问题解决

2

        asp.net默认的编码为utf-8,当与其它平台交互处理的字符串中有中文时往往会出现乱码,这是由于其它平台多采取GB2312编码,要解决这一问题,可编写一个函数,对字符串先转换再处理就行了,下面是该函数的源代码:

Imports System.Math

 Function URLEncoding(ByVal vstrIn As String)
        Dim strReturn As String
        strReturn = ""
        Dim i As Integer

        Dim ThisChr As String

        Dim innerCode, Hight8, Low8 As Integer

        For i = 1 To vstrIn.Length

            ThisChr = Mid(vstrIn, i, 1)

            If Abs(Asc(ThisChr)) < &HFF Then
                strReturn = strReturn & ThisChr
            Else
                innerCode = Asc(ThisChr)
                If innerCode < 0 Then
                    innerCode = innerCode + &H10000
                End If
                Hight8 = (innerCode And &HFF00) / &HFF
                Low8 = innerCode And &HFF
                strReturn = strReturn & "%" & Hex(Hight8) & "%" & Hex(Low8)
            End If
        Next
        URLEncoding = strReturn
    End Function

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值