C# 網路程式設計之webBrowser亂碼問題及解決知識
在使用PHP+MySQL編寫網頁時,曾近就因為顯示中文亂碼”口口口???”困擾我很長時間,沒想到在C#製作瀏覽器或獲取XML頁面時也經常會遇到顯示中文亂碼的問題,可想而知怎樣解決編碼問題或統一編碼問題是非常嚴重的問題。下面就講講我的一些理解及解決方法吧!
一.瀏覽器實現
前面我已經介紹了使用webBrowser控制元件實現"最簡單的瀏覽器"基本程式碼如下所示:
//名稱空間 using System.Net; using System.IO; //點選"瀏覽"按鈕 private void button1_Click(object sender, EventArgs e) { //輸入URL string url = textBox1.Text; var request = (HttpWebRequest)WebRequest.Create(url); //HTTP請求 var response = (HttpWebResponse)request.GetResponse(); //HTTP應答 //顯示webBrowser中 Stream stream = response.GetResponseStream(); //獲取應答流 StreamReader sr = new StreamReader(stream); //從位元組流中讀取字元 string content = sr.ReadToEnd(); webBrowser1.DocumentText = content; }
該方法通過獲取相應URL的應答內容,通過賦值資料流,再從位元組流中讀取內容賦值給webBrowser控制元件中實現最簡單的瀏覽器;但通過該方法常常會遇到現實中文字元亂碼問題,或者是顯示格式錯誤等問題.例如訪問google等.
PS:這裡有另外一種方法呼叫webBrowser的Navigate方法將指定位置的文件載入到控制元件中,其中一種過載方法Navigate(string)將制定的統一資源定位符URL處的文件載入到WebBrowser控制元件中替換上一個文件,而且實現該方法不會出現亂碼問題、排版問題、缺少http報錯問題.其實我很想知道封裝的該函式是如何實現的.
private void button1_Click(object sender, EventArgs e) { webBrowser1.Navigate(textBox1.Text.Trim()); }
二.亂碼問題
通過獲取網頁的響應字符集string str = response.CharacterSet(只讀屬性)可以發現,當字符集為utf-8時才能正常顯示,否則其他編碼方式都會出現中文亂碼;這裡最常出現的亂碼編碼方式為ISO-8859-1,big5,gbk,gb2312等;而utf-8通常能顯示中文.ISO-8859-1:又稱Latin-1或"西歐語言",是單位元組編碼,自身不能顯示中文,配合gbk或utf-8顯示中文,通常以byte[]形式儲存,以ISO-8859-1格式解碼會是亂碼,通常採用gb2313解碼;
big5:通行於臺灣、香港地區的一個繁體字編碼方案,俗稱”大五碼“.上面訪問香港google就是big5出現的亂碼.
utf-8:是一種針對Unicode的可變長度字元編碼,又稱萬國碼.它可以用來表示Unicode標準中的任何字元,且其編碼中的第一個位元組仍與ASCII相容,逐漸成為電子郵件、網頁及其他儲存或傳送文字的應用中,優先採用的編碼.
gb2312:是中華人民共和國國家漢字資訊交換用編碼,全稱"資訊交換用漢字編碼字符集",基本集共收入漢字6763個和非漢字圖形字元682個.gbk亦漢字編碼標準.
出現編碼方式的根本原因是在解析時使用的字元編碼和網頁的編碼方式不同,所以採用的解決方法通常是:
1.首先利用HttpWebResponse.CharacterSet屬性獲取字符集;
2.在根據不同的字符集設定相應的Encoding來避免亂碼.
三.解決方法
其中最簡單的方法是先獲取其指定網頁的字符集,在根據它的字符集採用相應的編碼方式進行解碼讀取.我們採用下面程式碼獲取該URL的字符集為"ISO-8859-1"
string str = response.CharacterSet;
MessageBox.Show(str);
在設定其對應的編碼方式,通過定義Encoding enc字元編碼方式,其方法GetEncoding("相應編碼方式")設定字元編碼,然後在StreamReader(stream,enc)中採用對應設定的編碼方式從位元組流中讀取內容.
private void button1_Click(object sender, EventArgs e)
{
//獲取輸入的URL
string url = textBox1.Text;
var request = (HttpWebRequest)WebRequest.Create(url); //HTTP請求
var response = (HttpWebResponse)request.GetResponse(); //HTTP應答
//顯示響應字符集
string str = response.CharacterSet;
MessageBox.Show(str);
//設定ISO-8859-1字元編碼方式
Encoding enc;
if (response.CharacterSet != "ISO-8859-1")
{
enc = Encoding.GetEncoding(response.CharacterSet);
}
else
{
enc = Encoding.GetEncoding("GBK");
}
//顯示webBrowser中
Stream stream = response.GetResponseStream(); //獲取應答流
StreamReader sr = new StreamReader(stream,enc); //從位元組流中讀取字元
string content = sr.ReadToEnd();
webBrowser1.DocumentText = content;
}
顯示結果如下:其中CharacterSet採用ISO-8859-1編碼方式,但從網頁原始碼中發現它的charset=gb2312所以我設定的Encoding.GetEncoding("GBK或GB2312").能正確顯示中文漢字:
其實當獲取指定網頁字符集時,採用指定編碼方式對其進行解碼的核心程式碼就是幾句:(同樣可設定webBrowser.DocumentStream)
Stream stream = response.GetResponseStream();
StreamReader sr = new StreamReader(stream, System.Text.Encoding.GetEncoding("gb2312"));
string content = sr.ReadToEnd();
也可以採用獲取到的文章內容content通過byte[] utf8Bytes = System.Text.Encoding.Convert(iso_8859_1, utf_8, isoBytes);這樣的語句轉換為相應的內容顯示;經常能看到這樣的通過byte[]轉換ISO-8859-1的方法,但本人沒有嘗試過.個人認為在讀入時就採用相對應的編碼方式比較好.
由於webBrowser是簡單的瀏覽器,肯定不能使用每一個頁面都去找相應的characterSet字符集,因此我們可以設定相應的函式,直接呼叫函式實現顯示內容:(程式碼感謝一位博主,http://blog.csdn.net/lemonay/article/details/8865939)
private static string GetHTMLbyWebRequest(string url)
{
//獲取輸入的URL
var request = (HttpWebRequest)WebRequest.Create(url); //HTTP請求
var response = (HttpWebResponse)request.GetResponse(); //HTTP應答
Encoding encoding = System.Text.Encoding.Default; //當前字元編碼方式
//響應狀態為OK
if (response.StatusDescription.ToUpper()=="OK") //大寫
{
//設定獲取連結中網頁的編碼格式
switch (response.CharacterSet.ToLower()) //小寫
{
case "gbk":
encoding = Encoding.GetEncoding("GBK");
break;
case "gb2312":
encoding = Encoding.GetEncoding("GB2312");
break;
case "utf-8":
encoding = Encoding.UTF8;
break;
case "iso-8859-1":
encoding = Encoding.GetEncoding("GBK"); //GB2312
break;
case "big5":
encoding = Encoding.GetEncoding("Big5");
break;
default:
encoding = Encoding.UTF8;
break;
}
//流操作
Stream stream = response.GetResponseStream();
StreamReader sr = new StreamReader(stream,encoding);
string content = sr.ReadToEnd();
File.WriteAllText("1.html", content, Encoding.UTF8);
//關閉釋放資源
stream.Close();
sr.Close();
response.Close();
return content;
}
else
{
MessageBox.Show("響應失敗!");
return string.Empty;
}
}
然後在點選按鈕事件中呼叫該函式即可:webBrowser1.DocumentText = GetHTMLbyWebRequest(textBox1.Text.Trim());就能實現訪問亂碼的網站,但網站還是有一個問題:在訪問sohu時是亂碼,其他網站基本都能正常訪問.這讓我有陷入思考中.下面是訪問google,同時在該函式中最後新增File.WriteAllText("text.html", content, Encoding.UTF8);還能獲取儲存靜態頁面.
//動態獲取網頁編碼方式並讀取
Encoding encoding = Encoding.GetEncoding(webBrowser.Document.Encoding);
StreamReader stream = new StreamReader(webBrowser.DocumentStream, encoding);
string conten = stream.ReadToEnd();
四.總結
文章主要是針對我在採用WebBrowser編寫簡單瀏覽器時遇到的中文亂碼問題,通常會顯示為"口口口"或"???",不同的編碼方式ISO-8859-1、GBK、Big5、utf-8採用相應的編碼方式即可避免.文章以PHP+MySQL遇到的中文亂碼開頭,這裡也以它結尾,在PHP+MySQL中需要注意兩個方面:(1).PHP網頁|MySQL|Apache|瀏覽器中|伺服器對應的編碼方式一致,就會避免亂碼問題,其中utf-8對應utf-8,gb2312(國標碼)對應txt中ANSI編碼方式;
(2).注意有無BOM問題(為識別Unicode檔案,以U+FEFF字元開頭,作為位元組順序標記byte-order mark,BOM來識別檔案中使用的編碼和位元組順序),通常Apache中charset設定為utf-8,所以採用UltraEdit設定檔案格式為utf-8無BOM另存為即可.
希望文章能幫助到大家,如果文章中有錯誤或不足之處,請大家海涵!
(By:Eastmount 2013-9-23 21點 http://blog.csdn.net/eastmount)