(转载)dotnet core 中文乱码 codepages

引子

转载自:http://www.jianshu.com/p/1c9c59c5749a

参考:.Net Core 控制台输出中文乱码

上文中我查阅了一些cli的源码, 闲来无事就继续翻代码, 冥冥之中自有天意, 在无尽的代码中, 我看到了这样一个注释

// by default, .NET Core doesn‘t have all code pages needed for Console apps.
// see the .NET Core Notes in https://msdn.microsoft.com/en-us/library/system.diagnostics.process(v=vs.110).aspx

dotnet core 团队的思路是好的, 提供一个比较小的程序集, 码农们按自己的需求自行添加需要的依赖, 可以生成更小的程序集, 完全同意. But, 我猜肯定有人坠坑过.

有人坠么?

随便google了一下得出以下结果

果不出我所料, 中奖的兄弟还不少, 不过也早有大神对此事进行过叙述, 并且早已在其文中给出解决方法, 大神的文章在此 难道.NET Core到R2连中文编码都不支持吗?(http://www.cnblogs.com/artech/archive/2016/05/18/5507092.html)
有人会问了, 那你还写个屁文干啥?

事还没完!

为啥没完? 因为看到大神文章的评论中一个兄弟在坑中还没爬上来. 川酷不能见死不救是不是?
据那位仁兄所说, 事情的经过是这样的.

        Console.WriteLine("你好, 世界!");
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        Console.WriteLine("你好, 世界!");

按大神文章所述, 注册了CodePages 编码则为UTF-8, 中文不应该乱码, 可事实是

难道大神也错了吗? 当然不会!

        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

正常情况下这句代码足矣解决问题, 依cli注释所说, 对于Console程序, 并没有添加所有的code page, 而且注释中给出的微软官方解决方案也是添加codepage 的dll程序集, 并添加上面那句代码.
这个时候我又找到了另外一个大神的blog,里面有另一种解决方案

    public static void Main(string[] args)
    {
        Console.OutputEncoding = System.Text.Encoding.UTF8;//第一种方式:指定编码
        //Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);//第二种方式

        Console.Read();
    }

既然有方案一, 川酷肯定要试一下.

        Console.WriteLine("你好, 世界!");
        Console.OutputEncoding=Encoding.UTF8;
        //Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        Console.WriteLine("你好, 世界!");

大神就是大神, 这招灵!

不过第二行的输出有一点小问题, 有兴趣的童鞋研究一下, 在此不再赘述.

让我带你飞!

依川酷的风格, 翻代码的时候到了! 既然问题出在Console中, 那就找Console的代码来看下. 有兴趣的可以在这里获取代码 . 让我们找到Console.cs这个文件, 可以看到相应的WriteLine方法的重载.

    [MethodImplAttribute(MethodImplOptions.NoInlining)]
    public static void WriteLine(String value)
    {
        Out.WriteLine(value);
    }

再看Out是个什么鬼.

    public static TextWriter Out
    {
        get { return Volatile.Read(ref s_out) ?? EnsureInitialized(ref s_out, () => CreateOutputWriter(OpenStandardOutput())); }
    }

然后我们发现s_out就是用于输出的TextWriter.
并且在第一次调用的时候会创建一个新的.

    private static TextWriter CreateOutputWriter(Stream outputStream)
    {
        return SyncTextWriter.GetSynchronizedTextWriter(outputStream == Stream.Null ?
            StreamWriter.Null :
            new StreamWriter(
                stream: outputStream,
                encoding: new ConsoleEncoding(OutputEncoding), // This ensures no prefix is written to the stream.
                bufferSize: DefaultConsoleBufferSize,
                leaveOpen: true) { AutoFlush = true });
    }

这样看来TextWriter的Encoding是使用的OutputEncoding, 那我们实践下, 这个初始的OutputEncoding到底是什么.

既然是UTF-8为何还是乱码? 此事还应该从微软的那句注释说起, 人家说了, 默认是没有添加codepage的, 即使你现在是UTF-8编码, 但是程序中没有codepage, 当然没办法处理. 我们来看看OutputEncoding的源码吧.

    public static Encoding OutputEncoding
    {
        get
        {
            return Volatile.Read(ref s_outputEncoding) ?? EnsureInitialized(ref s_outputEncoding, () => ConsolePal.OutputEncoding);
        }
        set
        {
            CheckNonNull(value, "value");

            lock (InternalSyncObject)
            {
                // Set the terminal console encoding.
                ConsolePal.SetConsoleOutputEncoding(value);

                // Before changing the code page we need to flush the data
                // if Out hasn‘t been redirected. Also, have the next call to
                // s_out reinitialize the console code page.
                if (Volatile.Read(ref s_out) != null && !s_isOutTextWriterRedirected)
                {
                    s_out.Flush();
                    Volatile.Write(ref s_out, null);
                }
                if (Volatile.Read(ref s_error) != null && !s_isErrorTextWriterRedirected)
                {
                    s_error.Flush();
                    Volatile.Write(ref s_error, null);
                }

                Volatile.Write(ref s_outputEncoding, (Encoding)value.Clone());
            }
        }
    }

我猜问题就出在了ConsolePal.SetConsoleOutputEncoding(value) 这一句.
我相信大家记得, 在我显性set了OutputEncoding为UTF-8之后控制台的中文显示就正常了. 也就是说对OutputEncoding做了set动作之后, 会强制Console窗口引入codepage文件.

Summary

比较一下两种解决方式, 其实两者有本质的不同, SetConsoleOutputEncoding是为这个控制台实例做编码的设置, 而 RegisterProvider 是为当前这个程序集添加codepage.
之所以 Encoding.RegisterProvider(CodePagesEncodingProvider.Instance)不起作用是因为前面的一句Console.WriteLine("你好, 世界!")已经使该命令行窗口初始化了编码. 执行Encoding.RegisterProvider(CodePagesEncodingProvider.Instance)并不对命令行窗口起作用, 在这里给做一个实验, 我相信大家就可以清楚中间到底发生了什么.
首先, 重复刚开始的代码.

        Console.WriteLine("你好, 世界!");
        // Console.OutputEncoding=Encoding.UTF8;
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        Console.WriteLine("你好, 世界!");

得到的结果是这样的.

然后为该命令行执行这句Console.OutputEncoding=Encoding.UTF8;. 再看下结果.

其实此时的RegisterProvider方法已经没有意义了, 因为命令行已经加载了codepage. 就是这样, 完结!

欢迎大家讨论, 如果有觉得不对或不妥的地方也希望大家可以指正, 我会努力写一些高质量的文章.

时间: 2024-10-12 22:44:20

(转载)dotnet core 中文乱码 codepages的相关文章

【转载】Servlet 中文乱码问题及解决方案剖析

转自:http://blog.csdn.net/xiazdong/article/details/7217022 一.常识了解 1.GBK包含GB2312,即如果通过GB2312编码后可以通过GBK解码,反之可能不成立; 2.java.nio.charset.Charset.defaultCharset() 获得平台默认字符编码: 3.getBytes() 是通过平台默认字符集进行编码: 二.中文乱码出现 在学习任何一门技术时,经常会有初学者遇到中文乱码问题,比如MySQL,是因为在安装时没有设

jsp中文乱码解决办法

一.JSP页面显示乱码 二.表单提交中文时出现乱码 三.数据库连接 大家在JSP的开发过程中,经常出现中文乱码的问题,可能一至困扰着您,我现在把我在JSP开发中遇到 的中文乱码的问题及解决办法写出来供大家参考. 一.JSP页面显示乱码下面的显示页面(display.jsp)就出现乱码: <html>< head>< title>JSP的中文处理</title> < meta http-equiv="Content-Type" con

解决Xshell和vim中文乱码(转载)

From:http://blog.csdn.net/lovey599/article/details/7275403 一般而言,乱码多是由于编码问题引起 的,在windows系统中,大多数情况下中文编码采用的是big5或utf-8两种,但是默认情况下确是big5,如果这样的话,请首先用locale命令查看你linux系统当前语系,执行LANG=zh_CN.big5修改语系.这里以utf8编码为例. 打开一个用utf8编码的中文文件,在vim中,执行:set encoding=utf-8 term

转载:Ununtu下中文乱码解决方案

转载: 添加中文字符编码: $sudo vim /var/lib/locales/supported.d/local #添加下面的中文字符集 zh_CN.GBK GBK zh_CN.GB2312 GB2312 zh_CN.GB18030 GB18030 使其生效: $sudo dpkg-reconfigure locales vim: 打开vim的配置文件,位置在/etc/vim/vimrc 在其中加入 set fileencodings=utf-8,gb2312,gbk,gb18030 set

Ubuntu14.04安装中文输入法以及解决Gedit中文乱码问题[转载]

转载自:http://www.cnblogs.com/zhcncn/p/4032321.html 写在前面:解决gedit 在txt文件格式出现乱码的问题,在我自己的操作中是需要把系统设置成中文显示环境的,不然这个问题没有解决.----tips by chsry. 1 设置中文显示环境 1. 打开System Settings 2. 打开Personal-> Language Support. 会弹出如下对话框,提示你“语言支持没安装完整”. 点击“Remind Me Later”. 3. 在“

[转载] linux下打开windows txt文件中文乱码问题

原文链接 在linux操作系统下,我们有时打开在windows下的txt文件,发现在windows下能正常显示的txt文件出现了中文乱码. 出现这种情况的原因为两种操作系统的中文压缩方式不同,在windows环境中中文压缩一般为gbk,而在linux环境中为utf8,这就导致了在windows下能正常显示 txt文件在linux环境下打开呈现了乱码状态. 解决方法:在linux用iconv命令,如乱码文件名为shujujiegou.txt,那么在终端输入如下命令: iconv -f gbk -t

.Net Core 控制台输出中文乱码

Net Core 控制台输出中文乱码的解决方法: public static void Main(string[] args)        {            Console.OutputEncoding = System.Text.Encoding.UTF8;//第一种方式:指定编码            //Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);//第二种方式                    

loadrunner 脚本和replaylog中的中文乱码问题(转载)

解决这个问题必须认识到一个事实就是,loadrunner和测试服务器交换数据使用的是utf8格式,但是展现在replaylog中是使用gb2312格式,而且在脚本中如何使用web_reg_find的时候也是使用的是gb2312格式,所以知道这个原理后,事情就好办多了. 首先使用关联函数web_reg_save_param将服务器返回的Server Response 内容保存为参数,接着利用 lr_convert_string_encoding函数进行编码格式转换即可. 此时注意---关联函数是一

解决PuTTY中文乱码【转载】

解决PuTTY中文乱码 转载:http://lhdeyx.blog.163.com/blog/static/3181969720091115113716947/ 打开putty,选择 Category中的Windows--->Appearance---> Font settings 把”字体”改为”Fixedsys”(或者其他中文字体),字符集为CHINEASE_GB2312 怎么还是乱码? 如果还是乱码的话,就执行以下命令,看看系统的字符集 echo $LANG $LANGUAGE哦,原来系