首页 后端开发 C#.Net教程 关于.NET(C#)正确读取中文编码文件的实例教程

关于.NET(C#)正确读取中文编码文件的实例教程

Apr 24, 2017 pm 04:56 PM
.net c#

首先如果读者对编码或者BOM还不熟悉的话,推荐先读这篇文章:.NET(C#):字符编码(Encoding)和字节顺序标记(BOM)。
中文编码基本可以分成两大类:
1. ANSI编码的扩展集合:比如GBK, GB2312, GB18030等,这类编码都不存在BOM(一些更新的标准中文编码,比如GB18030和GBK编码,都向后兼容GB2312编码)。
2. Unicode编码集合:比如UTF-8, UTF-16, UTF-32等。这类编码可以有BOM,也可以不加BOM。
3. 部分Unicode编码还存在具体字节次序问题(Endianess),就是所谓的Little endian和Big endian之分,不同此节次序对于不同的BOM,比如UTF16,不过UTF8不存在字节次序问题。

OK,了解了基本知识后,让我们回到主题,该如何正确打开中文文本文件。第一个需要确认的信息是:你的Unicode编码文件是否包含BOM?

如果包含BOM的话,那么一切好说!因为如果我们发现了BOM,我们就知道他的具体编码了。如果没有发现BOM,那就不是Unicode,我们用系统默认的ANSI扩展中文编码集打开文本文件就OK了。
而如果Unicode编码没有BOM的话(显然,你不能保证用户给你的所有Unicode文件都是有BOM的),那么你要手动从原始字节中判断他是GBK?还是UTF8?还是其他编码?。这个就需要具体的编码觉察算法了(可以google “charset|encoding detection”), 当然编码觉察算法不一定会100%准确,正是因为这点,Windows记事本会有Bush hid the facts bug。在Chrome浏览网页时,也会遇到乱码的情况的。个人感觉,Notepad++的编码觉察做的还是很准确的。
编码觉察算法有很多,比如这个工程:https://code.google.com/p/ude

 
如果Unicode都带BOM的话,则就不需要第三方类库了。不过也有一些需要说明的地方。

问题就是.NET中读取文本方法(File类和StreamReader)默认是以UTF8编码来读取的,因此此类GBK的文本文件直接用.NET打开(不指定编码的话)结果肯定是乱码!

首先这里最有效地解决方案是使用系统默认的ANSI扩展编码,也就是系统默认的非Unicode编码来读取文本,参考代码:

//输出系统默认非Unicode编码Console.WriteLine(Encoding.Default.EncodingName);//使用系统默认非Unicode编码来打开文件var fileContent = File.ReadAllText("C:\test.txt", Encoding.Default);
登录后复制

在简体中文的Windows系统下应该输出:

简体中文(GB2312)<文本内容省略>...

而且使用这个方法其实是不限于简体中文的。

当然也可以手动去指定一个编码,比如就是GBK编码,但是如果用指定的GBK编码去打开一个Unicode文件,文件还会打开成功吗?答案是仍然成功。原因是.NET在打开文件时默认会自动觉察BOM然后用根据BOM得到的编码去打开文件,如果没有BOM再用用户指定的编码区打开文件,如果用户没有指定编码,则使用UTF8编码。

这个”自动觉察BOM“的参数可以在StreamReader中构造函数中设置,对应detectEncodingFromByteOrderMarks参数。

但是在File类的相应方法中无法设置。(比如: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”参数为True,所以当发现该文件有BOM,.NET会通过BOM觉察到是Unicode文件,然后用Unicode去打开文件的。当然如果没有BOM,会使用指定的编码参数去打开文件。对于GB2312编码的文本,显然是没有BOM的,所以必须指定GB2312编码,否则.NET会用默认的UTF8编码去解析文件,是无法读取结果的。第三行出现乱码则是由于“自动觉察BOM”为False,.NET会直接用指定的GB2312编码去读取一个有BOM的Unicode编码文本文件,显然无法成功的。

当然还可以自己判断BOM,如果没有BOM的话,指定一个缺省编码去打开文本。我在以前一篇文章中写到过(.NET(C#):从文件中觉察编码)。

代码:

static void Main(){    PrintText("gb2312.txt");    PrintText("unicode.txt");}//根据文件自动觉察编码并输出内容static void PrintText(string path){    var enc = GetEncoding(path, Encoding.GetEncoding("GB2312"));    using (var sr = new StreamReader(path, enc))    {        Console.WriteLine(sr.ReadToEnd());    }}/// <summary>/// 根据文件尝试返回字符编码/// </summary>/// <param name="file">文件路径</param>/// <param name="defEnc">没有BOM返回的默认编码</param>/// <returns>如果文件无法读取,返回null。否则,返回根据BOM判断的编码或者缺省编码(没有BOM)。</returns>static Encoding GetEncoding(string file, Encoding defEnc){    using (var stream = File.OpenRead(file))    {        //判断流可读?        if (!stream.CanRead)            return null;        //字节数组存储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;    }}//辅助函数,判断字节中的值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编码(更具体:还会根据BOM返回Big或者Little-Endian的UTF16编码),而没有BOM的文件则会返回缺省值GB2312编码。

Related Posts:

.NET(C#):从文件中觉察编码

.NET(C#):字符编码(Encoding)和字节顺序标记(BOM)

.NET(C#):使用System.Text.Decoder类来处理“流文本”

.NET(C#):浅谈程序集清单资源和RESX资源

以上是关于.NET(C#)正确读取中文编码文件的实例教程的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

使用 C# 的活动目录 使用 C# 的活动目录 Sep 03, 2024 pm 03:33 PM

使用 C# 的 Active Directory 指南。在这里,我们讨论 Active Directory 在 C# 中的介绍和工作原理以及语法和示例。

C# 中的随机数生成器 C# 中的随机数生成器 Sep 03, 2024 pm 03:34 PM

C# 随机数生成器指南。在这里,我们讨论随机数生成器的工作原理、伪随机数和安全数的概念。

C# 序列化 C# 序列化 Sep 03, 2024 pm 03:30 PM

C# 序列化指南。这里我们分别讨论C#序列化对象的介绍、步骤、工作原理和示例。

C# 数据网格视图 C# 数据网格视图 Sep 03, 2024 pm 03:32 PM

C# 数据网格视图指南。在这里,我们讨论如何从 SQL 数据库或 Excel 文件加载和导出数据网格视图的示例。

C# 中的模式 C# 中的模式 Sep 03, 2024 pm 03:33 PM

C# 模式指南。在这里,我们讨论 C# 中模式的介绍和前 3 种类型,以及其示例和代码实现。

C# 中的质数 C# 中的质数 Sep 03, 2024 pm 03:35 PM

C# 素数指南。这里我们讨论c#中素数的介绍和示例以及代码实现。

C# 中的阶乘 C# 中的阶乘 Sep 03, 2024 pm 03:34 PM

C# 阶乘指南。这里我们讨论 C# 中阶乘的介绍以及不同的示例和代码实现。

c#多线程和异步的区别 c#多线程和异步的区别 Apr 03, 2025 pm 02:57 PM

多线程和异步的区别在于,多线程同时执行多个线程,而异步在不阻塞当前线程的情况下执行操作。多线程用于计算密集型任务,而异步用于用户交互操作。多线程的优势是提高计算性能,异步的优势是不阻塞 UI 线程。选择多线程还是异步取决于任务性质:计算密集型任务使用多线程,与外部资源交互且需要保持 UI 响应的任务使用异步。

See all articles