dotnet core(C#)下读取ANSI(GB2312)编码的文本

本文介绍在.NET Core环境下读取中文编码文件的解决方案,通过注册CodePagesEncodingProvider并使用GB2312编码读取文件,成功解决了中文乱码问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我要干啥

一个txt文本文件,里面存了上千个文件的完整路径。获取到这些文件的文件名,就想着尝试下在dotnet core下编一个小程序来自动完成。

程序的思路还是很简单的:首先将txt文件中的文件名按行读取到string[]类型变量中;而后用LastIndexOf函数查找最后一个"\\"字符,用SubString截取文件名;最后把得到的文件名列表保存到文件中。

using System;
using System.Collections.Generic;
using System.IO;

namespace GetFileNames
{
    class Program
    {
        private static string infile;
        private static string outfile;
        static void Main(string[] args)
        {
            if (args.Length >= 2)
            {
                infile = args[0];
                outfile = args[1];
                string[] inlines = File.ReadAllLines(infile);
                List<string> outlines = new List<string>();
                foreach (string line in inlines)
                {
                    int substart = line.LastIndexOf("/") + 1;
                    int sublength = line.Length - substart;
                    if (substart <= 0 || sublength <= 0)
                        outlines.Add("");
                    else
                        outlines.Add(line.Substring(substart, sublength));
                }
                File.WriteAllLines(outfile, outlines);
                Console.WriteLine("Mission complete!");
            }
        }
    }
}

代码很简单,跑起来吧。可是,在读取文件的时候却遇到了问题:文件中的中文读进来后全部变成了乱码!

问题出哪儿啦

肯定是编码的问题。于是用记事本打开了txt文件,看到右下角显示的文件编码为ANSI。

于是尝试改变读入文件的编码方式。也就是在File.ReadAllLines()函数中增加一个文件编码的参数。当然还要添加对引用
using System.Text;

string[] inlines = File.ReadAllLines(infile, Encoding.Default);

可是具体要增加那种编码呢?试了几个都不好使。后来使用Encoding.GetEncodings()方法获取了全部支持的编码格式,发现一共才8种:UTF8、UTF7、UTF32、Unicode、BigEndianUnicode、ASCII、Default。而我要读取的ANSI格式不再这个范围之内。

因为对字符编码也不太了解,于是上网搜了一下,发现cnblog上有一篇写的很好的文章:编码方式之ASCII、ANSI、Unicode概述

2、ANSI

ANSI全称(American National Standard Institite)美国国家标准学会(美国的一个非营利组织),首先ANSI不是指的一种特定的编码,而是不同地区扩展编码方式的统称,各个国家和地区所独立制定的兼容ASCII

但互相不兼容的字符编码,微软统称为ANSI编码

 (GBK是在国家标准GB2312基础上进行了扩容,包含的字符更多)

 

补充:在windows下输入命令行的黑框下,右键再点击属性可以看到当前的编码方式和代码页

代码页也称为“内码表”,是与特定语言的字符集相对应的一张表。操作系统中不同的语言和区域设置可能使用不同的代码页(代码页一般与其所直接对应的字符集之间并非完全等同,往往因为种种原因

(比如标准跟不上现实实践的需要)而会对字符集有所扩展)

根据这篇文章的描述,我们可以知道,输入的txt文件的编码格式应该是GB2312,于是将读取文件的代码改为

string[] inlines = File.ReadAllLines(infile, Encoding.GetEncoding("GB2312"));

于是,我的到了一个大大的错误提示!GB2312是不支持的编码名称。

于是查阅了Encoding 类的官方文档。发现了很多编码,Net Framework和.Net Core都没有支持。

代码页名称显示名称.NET Framework 支持.NET Core 支持
37IBM037IBM EBCDIC (美国-加拿大)  
437IBM437OEM 美国  
500IBM500IBM EBCDIC (国际)  
708ASMO-708阿拉伯语(ASMO 708)  
720DOS-720阿拉伯语(DOS)  
737ibm737希腊语(DOS)  
775ibm775波罗的语(DOS)  
850ibm850西欧(DOS)  
852ibm852中欧语(DOS)  
855IBM855OEM 西里尔语  
857ibm857土耳其语(DOS)  
858IBM00858OEM 多语言拉丁语 I  
860IBM860葡萄牙语(DOS)  
861ibm861冰岛语(DOS)  
862DOS-862希伯来语(DOS)  
863IBM863加拿大法语(DOS)  
864IBM864阿拉伯语(864)  
865IBM865北欧语(DOS)  
866cp866西里尔语(DOS)  
869ibm869现代希腊语(DOS)  
870IBM870IBM EBCDIC (多语言拉丁语-2)  
874windows-874泰语(Windows)  
875cp875IBM EBCDIC (现代希腊语)  
932shift_jis日语 (Shift-JIS)  
936gb2312简体中文(GB2312) 
949ks_c_5601-1987朝鲜语  
950big5繁体中文(Big5)  
1026IBM1026IBM EBCDIC (土耳其拉丁语-5)  
1047IBM01047IBM 拉丁语-1  
1140IBM01140IBM EBCDIC (美国-加拿大-欧洲)  
1141IBM01141IBM EBCDIC (德国-欧洲)  
1142IBM01142IBM EBCDIC (丹麦-挪威-欧洲)  
1143IBM01143IBM EBCDIC (芬兰-瑞典-欧洲)  
1144IBM01144IBM EBCDIC (意大利-欧洲)  
1145IBM01145IBM EBCDIC (西班牙-欧洲)  
1146IBM01146IBM EBCDIC (英国-欧洲)  
1147IBM01147IBM EBCDIC (法国-欧洲)  
1148IBM01148IBM EBCDIC (国际-欧洲)  
1149IBM01149IBM EBCDIC (冰岛语-欧洲)  
1200utf-16Unicode
1201unicodeFFFEUnicode (大字节序)
1250windows-1250中欧语(Windows)  
1251windows-1251西里尔语(Windows)  
1252GB2312西欧语(Windows) 
1253windows-1253希腊语(Windows)  
1254windows-1254土耳其语(Windows)  
1255windows-1255希伯来语(Windows)  
1256windows-1256阿拉伯语(Windows)  
1257windows-1257波罗的语(Windows)  
1258windows-1258越南语(Windows)  
1361Johab韩语(Johab)  
10000macintosh西欧(Mac)  
10001x-mac-日语日语(Mac)  
10002x-mac-chinesetrad繁体中文(Mac)  
10003x-mac-韩语朝鲜语(Mac) 
10004x-mac-arabic阿拉伯语(Mac)  
10005x-mac-hebrew希伯来语(Mac)  
10006x-mac-希腊语希腊语(Mac)  
10007x-mac-cyrillic西里尔语(Mac)  
10008x-mac-chinesesimp简体中文(Mac) 
10010x-mac罗马尼亚语(Mac)  
10017x-mac-乌克兰语乌克兰语(Mac)  
10021x-mac-泰语泰语(Mac)  
10029x-mac-ce中欧语(Mac)  
10079x-mac-冰岛语冰岛语(Mac)  
10081x-mac-turkish土耳其语(Mac)  
10082x-mac-克罗地亚语克罗地亚语(Mac)  
12000utf-32Unicode (UTF-32)
12001utf-32BEUnicode (UTF-16 32 大字节序)
20000x-中文-CNS繁体中文(CNS)  
20001x-cp20001TCA 台湾  
20002x-中文-Eten繁体中文(Eten)  
20003x-cp20003IBM5550 台湾  
20004x-cp20004TeleText 台湾  
20005x-cp20005Wang 台湾  
20105x-IA5西欧(IA5)  
20106x-IA5-德语德语(IA5)  
20107x IA5-瑞典语瑞典语(IA5)  
20108x-IA5-Norwegian挪威语(IA5)  
20127us-asciiUS-ASCII
20261x-cp20261T.61  
20269x-cp20269ISO-6937  
20273IBM273IBM EBCDIC (德国)  
20277IBM277IBM EBCDIC (丹麦-挪威)  
20278IBM278IBM EBCDIC (芬兰-瑞典)  
20280IBM280IBM EBCDIC (意大利)  
20284IBM284IBM EBCDIC (西班牙)  
20285IBM285IBM EBCDIC (英国)  
20290IBM290IBM EBCDIC (日语片假名)  
20297IBM297IBM EBCDIC (法国)  
20420IBM420IBM EBCDIC (阿拉伯语)  
20423IBM423IBM EBCDIC (希腊语)  
20424IBM424IBM EBCDIC (希伯来语)  
20833x-EBCDIC-KoreanExtendedIBM EBCDIC (朝鲜语扩展)  
20838IBM-泰语IBM EBCDIC (泰语)  
20866koi8-r西里尔语(KOI8-RU-R)  
20871IBM871IBM EBCDIC (冰岛语)  
20880IBM880IBM EBCDIC (西里尔语俄语)  
20905IBM905IBM EBCDIC (土耳其语)  
20924IBM00924IBM 拉丁语-1  
20932EUC-JP日语(JIS 0208-1990 和0212-1990)  
20936x-cp20936简体中文(GB2312-80) 
20949x-cp20949韩语 Wansung 
21025cp1025IBM EBCDIC (西里尔语塞尔维亚语-保加利亚语)  
21866koi8-ru-u西里尔语(KOI8-RU)  
28591iso-8859-1西欧语(ISO)
28592iso-8859-2中欧语(ISO)  
28593iso-8859-3拉丁语3(ISO)  
28594iso-8859-4波罗的语(ISO)  
28595iso-8859-5西里尔语(ISO)  
28596iso-8859-6阿拉伯语(ISO)  
28597iso-8859-7希腊语(ISO)  
28598iso-8859-8希伯来语(ISO-Visual) 
28599iso-8859-9土耳其语(ISO)  
28603iso-8859-13爱沙尼亚语(ISO)  
28605iso-8859-15拉丁语9(ISO)  
29001x-Europa欧洲  
38598iso-8859-8-i希伯来语(ISO-逻辑) 
50220iso-2022-jp日语(JIS) 
50221csISO2022JP日语(JIS-允许1字节假名) 
50222iso-2022-jp日语(JIS-允许1字节假名-SO/SI) 
50225iso-2022-kr朝鲜语(ISO) 
50227x-cp50227简体中文(ISO-2022) 
51932euc-jp日语(EUC) 
51936EUC-CN简体中文(EUC) 
51949euc-kr韩语(EUC) 
52936hz-gb-2312简体中文(HZ) 
54936GB18030简体中文(GB18030) 
57002x-iscii-deISCII 梵文 
57003x-iscii-beISCII 孟加拉语 
57004x-iscii-taISCII 泰米尔语 
57005x-iscii-teISCII 泰卢固语 
57006x-iscii-asISCII 阿萨姆语 
57007x-iscii-orISCII 奥里雅语 
57008x-iscii-kaISCII 埃纳德文 
57009x-iscii-maISCII 马拉雅拉姆语 
57010x-iscii-guISCII 古吉拉特语 
57011x-iscii-paISCII 旁遮普语 
65000utf-7Unicode (UTF-7)
65001utf-8Unicode (UTF-8)

那要怎么办呢!在错误信息中心提到了Encoding.RegisterProvider 方法。其中的一段描述似乎又有了一线希望:

利用 RegisterProvider 方法,你可以注册派生自 EncodingProvider 的类,使字符编码在不支持它们的平台上可用。 注册编码提供程序后,可通过调用任何 Encoding.GetEncoding 重载来检索它支持的编码。 如果有多个编码提供程序,Encoding.GetEncoding 方法将尝试从每个提供程序检索指定的编码,并从最近注册的提供程序开始。

使用 RegisterProvider 方法注册编码提供程序还会在传递 0的参数时,修改encoding.getencoding (int32)encoding.getencoding (int32,EncoderFallback,DecoderFallback)方法的行为:

  • 如果注册的提供程序是 CodePagesEncodingProvider,则在 Windows 操作系统上运行时,该方法将返回与系统活动代码页匹配的编码。

  • 自定义编码提供程序可以选择在其中一个 GetEncoding 方法重载传递 0的参数时要返回哪种编码。 提供程序还可以选择不通过让 EncodingProvider.GetEncoding 方法返回 null来返回编码。

顺着CodePagesEncodingProvider这条线找下去,在微软的官方文档,对CodePagesEncodingProvider.Instance 属性的描述中有这样一段话:

若要检索在 Windows 桌面的 .NET Framework 中存在但在 .NET Core 中不存在的编码,请执行以下操作:

 这段话就是解决问题的关键。

解决问题的方法:

  1. 安装System.Text.Encoding.CodePages NuGet包。也就是上面那段话中的第1点。
  2. 使用Encoding.RegisterProvider方法注册编码。对应上面那段话中的第2、3点。
  3. 使用Encoding.GetEncoding("GB2312")获取文本文件对应的编码。

完整代码如下:

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;


namespace GetFileNames
{
    class Program
    {
        private static string infile;
        private static string outfile;
        static void Main(string[] args)
        {
            // 注册编码
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            if (args.Length >= 2)
            {
                infile = args[0];
                outfile = args[1];
                // 获取并使用GB2312编码读取文本文件
                string[] inlines = File.ReadAllLines(infile, Encoding.GetEncoding("GB2312"));
                List<string> outlines = new List<string>();
                foreach (string line in inlines)
                {
                    int substart = line.LastIndexOf("/") + 1;
                    int sublength = line.Length - substart;
                    if (substart <= 0 || sublength <= 0)
                        outlines.Add("");
                    else
                        outlines.Add(line.Substring(substart, sublength));
                }
                File.WriteAllLines(outfile, outlines);
                Console.WriteLine("Mission complete!");
            }
        }
    }
}

不知大家有没有注意到,我再保存文件的时候没有指定编码方式,最后的得到的文件是UTF-8编码格式的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值