c#+mysql 中文亂碼


c#+mysql 中文亂碼

遇到一個奇怪的問題,C#讀取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);
}
-----------------------------------------------------------------------------------------------------------------

看到這個文章受到啟發,重要的一句是:

通過以上兩點,我們可以看到,只要在連接MySQL時,正確地設定了字符集,無論數據庫本身是使用什么格式編碼的,都能得到正確的結果。也許有人會以為寫數據時設定的字符集必需和讀數據時一致,事實上完全沒有必要。程序所要做的只是告訴 MySQL,目前操作MySQL使用的是什么字符集即可。因為MySQL會自動完成如下的轉換工作:

寫數據庫時用的字符集-->存諸數據的字符集-->讀取數據的字符集。

 

由此想我的問題可能是寫入時聲明的我的字符編碼與我實際的不符,C#中字符默認編碼為GB2312,於是程序改動如下:

1:在鏈接字符加入字符編碼聲明

<add key="mysqlconstr" value="UserId=root;Allow Zero Datetime=true;Charset=gb2312;Host=125.*.*.*;Database=dbname;Password=123456"/>

向mysql說明我的字符編碼是gb2312, 不要搞錯

2:在數據庫類中每一插入數據語句前加入編碼聲明

cmd = new MySqlCommand("set names gb2312;"+sql,conn);
    cmd.ExecuteNonQuery();   

期待已久的中文終於順利寫入了!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM