溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

.NET(C#)如何讀取中文編碼文件

發(fā)布時間:2020-10-30 12:11:21 來源:億速云 閱讀:200 作者:小新 欄目:編程語言

小編給大家分享一下.NET(C#)如何讀取中文編碼文件,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

首先如果讀者對編碼或者BOM還不熟悉的話,推薦先讀這篇文章:.NET(C#):字符編碼(Encoding)和字節(jié)順序標(biāo)記(BOM)。
中文編碼基本可以分成兩大類:
1. ANSI編碼的擴(kuò)展集合:比如GBK, GB2312, GB18030等,這類編碼都不存在BOM(一些更新的標(biāo)準(zhǔn)中文編碼,比如GB18030和GBK編碼,都向后兼容GB2312編碼)。
2. Unicode編碼集合:比如UTF-8, UTF-16, UTF-32等。這類編碼可以有BOM,也可以不加BOM。
3. 部分Unicode編碼還存在具體字節(jié)次序問題(Endianess),就是所謂的Little endian和Big endian之分,不同此節(jié)次序?qū)τ诓煌腂OM,比如UTF16,不過UTF8不存在字節(jié)次序問題。

OK,了解了基本知識后,讓我們回到主題,該如何正確打開中文文本文件。第一個需要確認(rèn)的信息是:你的Unicode編碼文件是否包含BOM?

如果包含BOM的話,那么一切好說!因為如果我們發(fā)現(xiàn)了BOM,我們就知道他的具體編碼了。如果沒有發(fā)現(xiàn)BOM,那就不是Unicode,我們用系統(tǒng)默認(rèn)的ANSI擴(kuò)展中文編碼集打開文本文件就OK了。
而如果Unicode編碼沒有BOM的話(顯然,你不能保證用戶給你的所有Unicode文件都是有BOM的),那么你要手動從原始字節(jié)中判斷他是GBK?還是UTF8?還是其他編碼?。這個就需要具體的編碼覺察算法了(可以google “charset|encoding detection”), 當(dāng)然編碼覺察算法不一定會100%準(zhǔn)確,正是因為這點(diǎn),Windows記事本會有Bush hid the facts bug。在Chrome瀏覽網(wǎng)頁時,也會遇到亂碼的情況的。個人感覺,Notepad++的編碼覺察做的還是很準(zhǔn)確的。
編碼覺察算法有很多,比如這個工程:https://code.google.com/p/ude


如果Unicode都帶BOM的話,則就不需要第三方類庫了。不過也有一些需要說明的地方。

問題就是.NET中讀取文本方法(File類和StreamReader)默認(rèn)是以UTF8編碼來讀取的,因此此類GBK的文本文件直接用.NET打開(不指定編碼的話)結(jié)果肯定是亂碼!

首先這里最有效地解決方案是使用系統(tǒng)默認(rèn)的ANSI擴(kuò)展編碼,也就是系統(tǒng)默認(rèn)的非Unicode編碼來讀取文本,參考代碼:

//輸出系統(tǒng)默認(rèn)非Unicode編碼Console.WriteLine(Encoding.Default.EncodingName);//使用系統(tǒng)默認(rèn)非Unicode編碼來打開文件var fileContent = File.ReadAllText("C:\test.txt", Encoding.Default);

在簡體中文的Windows系統(tǒng)下應(yīng)該輸出:

簡體中文(GB2312)<文本內(nèi)容省略>...

而且使用這個方法其實是不限于簡體中文的。

當(dāng)然也可以手動去指定一個編碼,比如就是GBK編碼,但是如果用指定的GBK編碼去打開一個Unicode文件,文件還會打開成功嗎?答案是仍然成功。原因是.NET在打開文件時默認(rèn)會自動覺察BOM然后用根據(jù)BOM得到的編碼去打開文件,如果沒有BOM再用用戶指定的編碼區(qū)打開文件,如果用戶沒有指定編碼,則使用UTF8編碼。

這個”自動覺察BOM“的參數(shù)可以在StreamReader中構(gòu)造函數(shù)中設(shè)置,對應(yīng)detectEncodingFromByteOrderMarks參數(shù)。

但是在File類的相應(yīng)方法中無法設(shè)置。(比如:File.ReadAllText)。

比如下面代碼,分別用:

GB2312編碼,自動覺察BOM 來讀取GB2312文本

GB2312編碼,自動覺察BOM 來讀取Unicode文本

GB2312編碼,不覺察BOM 來讀取Unicode文本

static void Main(){    var gb2312 = Encoding.GetEncoding("GB2312");    //用GB2312編碼,自動覺察BOM 來讀取GB2312文本    ReadFile("gbk.txt", gb2312, true);    //用GB2312編碼,自動覺察BOM 來讀取Unicode文本    ReadFile("unicode.txt", gb2312, true);    //用GB2312編碼,不覺察BOM 來讀取Unicode文本    ReadFile("unicode.txt", gb2312, false);}//通過StreamReader讀取文本 static void ReadFile(string path, Encoding enc, bool detectEncodingFromByteOrderMarks){    StreamReader sr;    using (sr = new StreamReader(path, enc, detectEncodingFromByteOrderMarks))    {        Console.WriteLine(sr.ReadToEnd());    }}

輸出:

a劉a劉???

第三行是亂碼。

看到上面,使用GB2312編碼去打開Unicode文件也會成功的。因為“自動覺察BOM”參數(shù)為True,所以當(dāng)發(fā)現(xiàn)該文件有BOM,.NET會通過BOM覺察到是Unicode文件,然后用Unicode去打開文件的。當(dāng)然如果沒有BOM,會使用指定的編碼參數(shù)去打開文件。對于GB2312編碼的文本,顯然是沒有BOM的,所以必須指定GB2312編碼,否則.NET會用默認(rèn)的UTF8編碼去解析文件,是無法讀取結(jié)果的。第三行出現(xiàn)亂碼則是由于“自動覺察BOM”為False,.NET會直接用指定的GB2312編碼去讀取一個有BOM的Unicode編碼文本文件,顯然無法成功的。

當(dāng)然還可以自己判斷BOM,如果沒有BOM的話,指定一個缺省編碼去打開文本。我在以前一篇文章中寫到過(.NET(C#):從文件中覺察編碼)。

代碼:

static void Main(){    PrintText("gb2312.txt");    PrintText("unicode.txt");}//根據(jù)文件自動覺察編碼并輸出內(nèi)容static void PrintText(string path){    var enc = GetEncoding(path, Encoding.GetEncoding("GB2312"));    using (var sr = new StreamReader(path, enc))    {        Console.WriteLine(sr.ReadToEnd());    }}/// <summary>/// 根據(jù)文件嘗試返回字符編碼/// </summary>/// <param name="file">文件路徑</param>/// <param name="defEnc">沒有BOM返回的默認(rèn)編碼</param>/// <returns>如果文件無法讀取,返回null。否則,返回根據(jù)BOM判斷的編碼或者缺省編碼(沒有BOM)。</returns>static Encoding GetEncoding(string file, Encoding defEnc){    using (var stream = File.OpenRead(file))    {        //判斷流可讀?        if (!stream.CanRead)            return null;        //字節(jié)數(shù)組存儲BOM        var bom = new byte[4];        //實際讀入的長度        int readc;        readc = stream.Read(bom, 0, 4);        if (readc >= 2)        {            if (readc >= 4)            {                //UTF32,Big-Endian                if (CheckBytes(bom, 4, 0x00, 0x00, 0xFE, 0xFF))                    return new UTF32Encoding(true, true);                //UTF32,Little-Endian                if (CheckBytes(bom, 4, 0xFF, 0xFE, 0x00, 0x00))                    return new UTF32Encoding(false, true);            }            //UTF8            if (readc >= 3 && CheckBytes(bom, 3, 0xEF, 0xBB, 0xBF))                return new UTF8Encoding(true);            //UTF16,Big-Endian            if (CheckBytes(bom, 2, 0xFE, 0xFF))                return new UnicodeEncoding(true, true);            //UTF16,Little-Endian            if (CheckBytes(bom, 2, 0xFF, 0xFE))                return new UnicodeEncoding(false, true);        }        return defEnc;    }}//輔助函數(shù),判斷字節(jié)中的值static bool CheckBytes(byte[] bytes, int count, params int[] values){    for (int i = 0; i < count; i++)        if (bytes[i] != values[i])            return false;    return true;}

上面代碼,對于Unicode文本,GetEncoding方法會返回UTF16編碼(更具體:還會根據(jù)BOM返回Big或者Little-Endian的UTF16編碼),而沒有BOM的文件則會返回缺省值GB2312編碼。

Related Posts:

.NET(C#):從文件中覺察編碼

.NET(C#):字符編碼(Encoding)和字節(jié)順序標(biāo)記(BOM)

.NET(C#):使用System.Text.Decoder類來處理“流文本”

.NET(C#):淺談程序集清單資源和RESX資源

以上是.NET(C#)如何讀取中文編碼文件的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

ne
AI