• C#猜测识别文件编码


    项目 gitee地址:https://gitee.com/dhclly/IceDog.SmallProject/tree/master/src/IceDog.SmallProject.CodeConvert

    C#猜测识别文件编码

    测试句子: This is a good time. 这是个好时光。

    除了 ascii 只有英文,其他都是中英文都有

    主要判断的编码有

    • ascii
    • gb18030
    • gb2312
    • gbk
    • utf8
    • utf8WithBOM
    • Unicode utf16 LE
    • Unicode Big Endian utf16 BE

    其中ANSI是默认的编码方式,对于英文文件是ASCII编码,
    对于简体中文文件默认是GB2312编码(只针对Windows简体中文版,如果是繁体中文版默认会采用Big5码)

    Unicode其实是UTF-16 endian big编码方式,这个把带有BOM的小端序UTF-16
    称作Unicode而又不详细说明,也是微软的习惯;

    而Unicode big endian则是带有BOM的大端序编码方式

    EF BB BF 239 187 191 UTF-8  
    FE FF 254 255  UTF-16 BE (big-endian)
    FF FE 255 254  UTF-16 LE (little-endian)
    00 00 FE FF 00 00 254 255  UTF-32 BE (big-endian)
    FF FE 00 00 255 254 00 00  UTF-32 LE (little-endian)
    

    需要引入 NuGet :System.Text.Encoding.CodePages

    UTF-8是一种变长字节编码方式。对于某一个字符的UTF-8编码,
    如果只有一个字节则其最高二进制位为0;如果是多字节,
    其第一个字节从最高位开始,连续的二进制位值为1的
    个数决定了其编码的位数,其余各字节均以10开头。
    UTF-8最多可用到6个字节。

    • 1字节:0xxxxxxx
    • 2字节:110xxxxx 10xxxxxx
    • 3字节:1110xxxx 10xxxxxx 10xxxxxx
    • 4字节:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

    • 0000 0000 0x00
    • 1000 0000 0x80
    • 1100 0000 0xC0
    • 1110 0000 0xE0
    • 1111 0000 0xF0
    • 1111 1000 0xF8
    • 1111 1100 0xFC
    • 1111 1101 0xFD

    参考文章

    源码

    也可以直接去gitee去看代码

    TextCodeGuessHelper.cs

    /*
     * 取得一个文本文件的编码方式。如果无法在文件头部找到有效的前导符,Encoding.Default将被返回。
     * 文件的字符集在Windows下有两种,一种是ANSI,一种Unicode。
     * 对于Unicode,Windows支持了它的三种编码方式,小尾编码(Unicode),大尾编码(BigEndianUnicode),UTF-8编码。
     * 我们可以从文件的头部来区分一个文件是属于哪种编码。
     * 当头部开始的两个字节为 FF FE时,是Unicode的小尾编码;
     * 当头部的两个字节为FE FF时,是Unicode的大尾编码;
     * 当头部两个字节为EF BB BF时,是Unicode的UTF-8编码;
     * 当它不为这些时,则是ANSI(中文是GBK系列)编码。
     */
    
    
    using System;
    using System.IO;
    using System.Text;
    
    namespace IceDog.SmallProject.CodeConvert
    {
        /// <summary>
        /// 文本编码猜测帮助器
        /// <para>在调用其他方法前,先调用TextCodeGuessHelper.RegisterMoreEncoding()</para>
        /// </summary>
        public static class TextCodeGuessHelper
        {
            static TextCodeGuessHelper()
            {
            }
    
            /// <summary>
            /// 注册更多的编码类型类型
            /// </summary>
            /// <remarks>
            /// <para>需要引入 NuGet包:System.Text.Encoding.CodePages</para>
            /// <para>调用下面的编码类型需要先调用此方法</para>
            /// <para>详情链接:https://docs.microsoft.com/zh-cn/dotnet/api/system.text.encoding.registerprovider?redirectedfrom=MSDN&view=netframework-4.8#System_Text_Encoding_RegisterProvider_System_Text_EncodingProvider_</para>
            /// </remarks>
            public static void RegisterMoreEncoding()
            {
                Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            }
    
            public static Encoding UTF8 => Encoding.UTF8;
            public static Encoding Unicode => Encoding.Unicode;
            public static Encoding BigEndianUnicode => Encoding.BigEndianUnicode;
            public static Encoding ASCII => Encoding.ASCII;
            public static Encoding UTF16BE => Encoding.BigEndianUnicode;
            public static Encoding UTF16LE => Encoding.Unicode;
            public static Encoding GB2312 => Encoding.GetEncoding("GB2312");
            public static Encoding GBK => Encoding.GetEncoding("GBK");
            public static Encoding GB18030 => Encoding.GetEncoding("GB18030");
            /// <summary>
            /// 获取编码
            /// </summary>
            /// <param name="name">编码名称,如(UTF-8)</param>
            /// <returns></returns>
            public static Encoding GetEncoding(string name) => Encoding.GetEncoding(name);
    
            public static Encoding GuessFileEncoding(string filename)
            {
                if (!File.Exists(filename))
                {
                    throw new Exception("文件 " + filename + " 不存在!");
                }
                using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
                {
                    return GuessStreamEncoding(fs);
                }
            }
    
            public static Encoding GuessStreamEncoding(Stream stream)
            {
                if (!stream.CanRead)
                {
                    return null;
                }
                using (var br = new BinaryReader(stream))
                {
                    var buffer = br.ReadBytes(3);
                    if (buffer[0] == 0xFE && buffer[1] == 0xFF)//FE FF 254 255  UTF-16 BE (big-endian)
                    {
                        return Encoding.BigEndianUnicode;
                    }
    
                    if (buffer[0] == 0xFF && buffer[1] == 0xFE)//FF FE 255 254  UTF-16 LE (little-endian)
                    {
                        return Encoding.Unicode;
                    }
                    if (buffer[0] == 0xEF && buffer[1] == 0xBB & buffer[2] == 0xBF)//EF BB BF 239 187 191 UTF-8 
                    {
                        return Encoding.UTF8;//with BOM
                    }
    
                    if (IsUtf8WithoutBom(stream))
                    {
                        return Encoding.UTF8;//without BOM
                    }
                    if (IsPlainASCII(stream))
                    {
                        return Encoding.ASCII; //默认返回ascii编码
                    }
                    return GBK;
                }
            }
    
            public static bool IsPlainASCII(string path)
            {
                using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
                {
                    return IsPlainASCII(fs);
                }
    
            }
            private static bool IsPlainASCII(Stream stream)
            {
                bool isAllASCII = true;
                long totalLength = stream.Length;
                stream.Seek(0, SeekOrigin.Begin);//重置 position 位置
                using (var br = new BinaryReader(stream, Encoding.Default, true))
                {
                    for (long i = 0; i < totalLength; i++)
                    {
                        byte b = br.ReadByte();
                        /*
                         * 原理是
                         * 0x80     1000 0000
                         * &
                         * 0x75 (p) 0111 0101
                         * ASCII字符都比128小,与运算自然都是0
                         */
                        if ((b & 0x80) != 0)// (1000 0000): 值小于0x80的为ASCII字符    
                        {
                            isAllASCII = false;
                            break;
                        }
                    }
                }
                return isAllASCII;
            }
            /// <summary>   
            /// 通过给定的文件流,判断文件的编码类型
            /// </summary>   
            /// <param name="fs">文件流</param>   
            /// <param name="defaultEncoding">默认编码</param>   
            /// <returns>文件的编码类型</returns>   
            private static bool IsUtf8WithoutBom(Stream stream)
            {
                stream.Seek(0, SeekOrigin.Begin);//重置 position 位置
                bool isAllASCII = true;
                long totalLength = stream.Length;
                long nBytes = 0;
                using (var br = new BinaryReader(stream, Encoding.Default, true))
                {
                    for (long i = 0; i < totalLength; i++)
                    {
                        byte b = br.ReadByte();
                        // (1000 0000): 值小于0x80的为ASCII字符    
                        // 等同于 if(b < 0x80 )
                        if ((b & 0x80) != 0) //0x80 128
                        {
                            isAllASCII = false;
                        }
                        if (nBytes == 0)
                        {
                            if (b >= 0x80)
                            {
                                if (b >= 0xFC && b <= 0xFD) { nBytes = 6; }//此范围内为6字节UTF-8字符
                                else if (b >= 0xF8) { nBytes = 5; }// 此范围内为5字节UTF-8字符
                                else if (b >= 0xF0) { nBytes = 4; }// 此范围内为4字节UTF-8字符    
                                else if (b >= 0xE0) { nBytes = 3; }// 此范围内为3字节UTF-8字符    
                                else if (b >= 0xC0) { nBytes = 2; }// 此范围内为2字节UTF-8字符    
                                else { return false; }
                                nBytes--;
                            }
                        }
                        else
                        {
                            if ((b & 0xC0) != 0x80) { return false; }//0xc0 192  (11000000): 值介于0x80与0xC0之间的为无效UTF-8字符    
                            nBytes--;
                        }
                    }
                }
                if (nBytes > 0)
                {
                    return false;
                }
                if (isAllASCII)
                {
                    return false;
                }
                return true;
            }
    
            public static string ReadFile(string path, Encoding encoding)
            {
                using (StreamReader sr = new StreamReader(path, encoding, true))
                {
                    return sr.ReadToEnd();
                }
            }
            public static string ReadStream(Stream stream, Encoding encoding)
            {
                if (!stream.CanRead)
                {
                    return null;
                }
                using (StreamReader sr = new StreamReader(stream, encoding, true))
                {
                    return sr.ReadToEnd();
                }
            }
            /// <summary>
            /// 很巧妙的判断方式
            /// </summary>
            /// <param name="fileName"></param>
            /// <returns></returns>
            /// <remarks>参考:https://blog.csdn.net/capricio/article/details/83023828</remarks>
            public static Encoding IsGBKOrUTF8(string fileName)
            {
                var utf8Str = ReadFile(fileName, UTF8);
                var gbkStr = ReadFile(fileName, GBK);
                return utf8Str.Length <= gbkStr.Length ? UTF8 : GBK;
            }
        }
    }
    
    
  • 相关阅读:
    未来简史之数据主义(Dataism)
    10分钟看懂《人类简史》和《未来简史》
    SignalR来做实时Web聊天
    .Net Core应用搭建的分布式邮件系统设计
    AspNetCore-MVC实战系列(四)之结尾
    AspNetCore-MVC实战系列(三)之个人中心
    AspNetCore-MVC实战系列(二)之通过绑定邮箱找回密码
    AspNetCore
    爱留图
    .NetCore上传多文件的几种示例
  • 原文地址:https://www.cnblogs.com/DHclly/p/11648781.html
Copyright © 2020-2023  润新知