搜索
首页后端开发C#.Net教程关于.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)14b8d1cdd206e5cbcfed886eb0f25e83...

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

当然也可以手动去指定一个编码,比如就是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
如何使用C#编写时间序列预测算法如何使用C#编写时间序列预测算法Sep 19, 2023 pm 02:33 PM

如何使用C#编写时间序列预测算法时间序列预测是一种通过分析过去的数据来预测未来数据趋势的方法。它在很多领域,如金融、销售和天气预报中有广泛的应用。在本文中,我们将介绍如何使用C#编写时间序列预测算法,并附上具体的代码示例。数据准备在进行时间序列预测之前,首先需要准备好数据。一般来说,时间序列数据应该具有足够的长度,并且是按照时间顺序排列的。你可以从数据库或者

如何使用Redis和C#开发分布式事务功能如何使用Redis和C#开发分布式事务功能Sep 21, 2023 pm 02:55 PM

如何使用Redis和C#开发分布式事务功能引言分布式系统的开发中,事务处理是一项非常重要的功能。事务处理能够保证在分布式系统中的一系列操作要么全部成功,要么全部回滚。Redis是一种高性能的键值存储数据库,而C#是一种广泛应用于开发分布式系统的编程语言。本文将介绍如何使用Redis和C#来实现分布式事务功能,并提供具体代码示例。I.Redis事务Redis

如何实现C#中的人脸识别算法如何实现C#中的人脸识别算法Sep 19, 2023 am 08:57 AM

如何实现C#中的人脸识别算法人脸识别算法是计算机视觉领域中的一个重要研究方向,它可以用于识别和验证人脸,广泛应用于安全监控、人脸支付、人脸解锁等领域。在本文中,我们将介绍如何使用C#来实现人脸识别算法,并提供具体的代码示例。实现人脸识别算法的第一步是获取图像数据。在C#中,我们可以使用EmguCV库(OpenCV的C#封装)来处理图像。首先,我们需要在项目

Redis在C#开发中的应用:如何实现高效的缓存更新Redis在C#开发中的应用:如何实现高效的缓存更新Jul 30, 2023 am 09:46 AM

Redis在C#开发中的应用:如何实现高效的缓存更新引言:在Web开发中,缓存是提高系统性能的常用手段之一。而Redis作为一款高性能的Key-Value存储系统,能够提供快速的缓存操作,为我们的应用带来了不少便利。本文将介绍如何在C#开发中使用Redis,实现高效的缓存更新。Redis的安装与配置在开始之前,我们需要先安装Redis并进行相应的配置。你可以

分享几个.NET开源的AI和LLM相关项目框架分享几个.NET开源的AI和LLM相关项目框架May 06, 2024 pm 04:43 PM

当今人工智能(AI)技术的发展如火如荼,它们在各个领域都展现出了巨大的潜力和影响力。今天大姚给大家分享4个.NET开源的AI模型LLM相关的项目框架,希望能为大家提供一些参考。https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectPicks.mdSemanticKernelSemanticKernel是一种开源的软件开发工具包(SDK),旨在将大型语言模型(LLM)如OpenAI、Azure

如何使用C#编写动态规划算法如何使用C#编写动态规划算法Sep 20, 2023 pm 04:03 PM

如何使用C#编写动态规划算法摘要:动态规划是求解最优化问题的一种常用算法,适用于多种场景。本文将介绍如何使用C#编写动态规划算法,并提供具体的代码示例。一、什么是动态规划算法动态规划(DynamicProgramming,简称DP)是一种用来求解具有重叠子问题和最优子结构性质的问题的算法思想。动态规划将问题分解成若干个子问题来求解,通过记录每个子问题的解,

C#的就业前景如何C#的就业前景如何Oct 19, 2023 am 11:02 AM

无论您是初学者还是有经验的专业人士,掌握C#将为您的职业发展铺平道路。

如何实现C#中的图像压缩算法如何实现C#中的图像压缩算法Sep 19, 2023 pm 02:12 PM

如何实现C#中的图像压缩算法摘要:图像压缩是图像处理领域中的一个重要研究方向,本文将介绍在C#中实现图像压缩的算法,并给出相应的代码示例。引言:随着数字图像的广泛应用,图像压缩成为了图像处理中的重要环节。压缩能够减小存储空间和传输带宽,并能提高图像处理的效率。在C#语言中,我们可以通过使用各种图像压缩算法来实现对图像的压缩。本文将介绍两种常见的图像压缩算法:

See all articles

热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.能量晶体解释及其做什么(黄色晶体)
2 周前By尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
4 周前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

禅工作室 13.0.1

禅工作室 13.0.1

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

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

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

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能