【问题标题】:How to find out the Encoding of a File? C#如何找出文件的编码? C#
【发布时间】:2011-03-25 04:03:43
【问题描述】:

好吧,我需要找出我在某个目录中找到的哪些文件是 UTF8 编码的,或者是 ANSI 编码的,以更改我稍后决定的其他编码。我的问题是.. 我怎样才能确定文件是 UTF8 还是 ANSI 编码?这两种编码实际上都可以在我的文件中使用。

【问题讨论】:

    标签: c#


    【解决方案1】:

    请看这两篇codeproject文章——单纯从文件内容中找出文件编码并非易事:

    【讨论】:

      【解决方案2】:

      没有可靠的方法来做到这一点(因为文件可能只是随机二进制文件),但是由 Windows 记事本软件完成的过程在 Micheal S Kaplan 的博客中有详细说明:

      http://www.siao2.com/2007/04/22/2239345.aspx

      1. 检查前两个字节; 1. 如果存在 UTF-16 LE BOM,则将其视为(并加载)为“Unicode”文件; 2.如果存在UTF-16 BE BOM,则将其视为(并加载)为“Unicode(Big Endian)”文件; 3. 如果前两个字节看起来像 UTF-8 BOM 的开头,则检查下一个字节,如果我们有 UTF-8 BOM,则将其视为(并加载)为“UTF-8”文件;
      2. 检查 IsTextUnicode 以查看该函数是否认为它是无 BOM 的 UTF-16 LE,如果是,则将其视为(并加载)为“Unicode”文件;
      3. 使用 1998 年的原始 RFC 2279 定义检查它是否为 UTF-8,然后将其视为(并加载)为“UTF-8”文件;
      4. 假设 ANSI 文件使用机器的默认系统代码页。

      现在注意有一些漏洞 在这里,就像第 2 步一样 没有 BOM 的情况不太好 UTF-16 BE(甚至可能存在错误 在这里,我不确定——如果是这样,那是一个错误 在记事本中超出任何错误 IsTextUnicode)。

      【讨论】:

      • 如果您为 detectEncodingFromByteOrderMarks 参数传递 true,StreamReader 会自动执行此操作。 msdn.microsoft.com/en-us/library/7bc2hwcb.aspx
      • 谢谢,我不知道 .net 对此程序有内部支持!
      • 在我的测试中,“detectEncodingFromByteOrderMarks”标志未检测到 ANSI 编码
      • StreamReader 肯定检测不到 ANSI。
      • @ICantSeeSharp How-to 检测 ANSI ?
      【解决方案3】:

      http://msdn.microsoft.com/en-us/netframework/aa569610.aspx#Question2

      没有很好的方法来检测 任意 ANSI 代码页,尽管有 已经做了一些尝试 基于某些概率 文本中间的字节序列。 我们不会在 StreamReader 中尝试这样做。一种 很少有像 XML 或 HTML 这样的文件格式 一种指定字符集的方法 在文件的第一行,所以 Web 浏览器、数据库和类,如 XmlTextReader 可以读取这些文件 正确。但是许多文本文件没有 建立这种类型的信息 在。

      【讨论】:

        【解决方案4】:

        Unicode/UTF8/UnicodeBigEndian 被认为是不同的类型。 ANSI 被认为与 UTF8 相同。

        public class EncodingType
        {
            public static System.Text.Encoding GetType(string FILE_NAME)
            {
                FileStream fs = new FileStream(FILE_NAME, FileMode.Open, FileAccess.Read);
                Encoding r = GetType(fs);
                fs.Close();
                return r;
            }
        
            public static System.Text.Encoding GetType(FileStream fs)
            {
                byte[] Unicode = new byte[] { 0xFF, 0xFE, 0x41 };
                byte[] UnicodeBIG = new byte[] { 0xFE, 0xFF, 0x00 };
                byte[] UTF8 = new byte[] { 0xEF, 0xBB, 0xBF }; //with BOM
                Encoding reVal = Encoding.Default;
        
                BinaryReader r = new BinaryReader(fs, System.Text.Encoding.Default);
                int i;
                int.TryParse(fs.Length.ToString(), out i);
                byte[] ss = r.ReadBytes(i);
                if (IsUTF8Bytes(ss) || (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF))
                {
                    reVal = Encoding.UTF8;
                }
                else if (ss[0] == 0xFE && ss[1] == 0xFF && ss[2] == 0x00)
                {
                    reVal = Encoding.BigEndianUnicode;
                }
                else if (ss[0] == 0xFF && ss[1] == 0xFE && ss[2] == 0x41)
                {
                    reVal = Encoding.Unicode;
                }
                r.Close();
                return reVal;
        
            }
        
            private static bool IsUTF8Bytes(byte[] data)
            {
                int charByteCounter = 1;  
                byte curByte; 
                for (int i = 0; i < data.Length; i++)
                {
                    curByte = data[i];
                    if (charByteCounter == 1)
                    {
                        if (curByte >= 0x80)
                        {
                            while (((curByte <<= 1) & 0x80) != 0)
                            {
                                charByteCounter++;
                            }
                             
                            if (charByteCounter == 1 || charByteCounter > 6)
                            {
                                return false;
                            }
                        }
                    }
                    else
                    {
                        if ((curByte & 0xC0) != 0x80)
                        {
                            return false;
                        }
                        charByteCounter--;
                    }
                }
                if (charByteCounter > 1)
                {
                    throw new Exception("Error byte format");
                }
                return true;
            }
        
        }
        

        【讨论】:

        • 这看起来像是一段很棒的代码。但是,UTF16 LE 和 UTF16-BE 不应该分别具有签名“FF FE”和“FE FF”吗?您添加了一个额外的字节。见:unicode.org/faq/utf_bom.html#bom4
        • 顺便说一下,您的 IsUTF8Bytes() 函数与此处显示的 Christoph 的答案相比如何:stackoverflow.com/a/1031773/848344
        • @DanW:我不知道 Christoph 的答案来自哪里,我发布的代码是我工作过的项目的一部分,由一个队友编写。
        • 我建议使用using statement 而不是手动关闭/处置对象,以确保即使在发生意外异常时也能处置这些对象。
        【解决方案5】:
           public static System.Text.Encoding GetEncoding(string filepath, Encoding defaultEncoding)
            {
                // will fall to defaultEncoding if file does not have BOM
        
                using (var reader = new StreamReader(filepath, defaultEncoding, true))
                {
                    reader.Peek(); //need it
                    return reader.CurrentEncoding;
                }
            }
        

        检查Byte Order Mark (BOM)

        要查看 BOM,您需要以十六进制视图查看文件。

        记事本在状态栏显示文件编码,但如果文件没有设置BOM,则可以只是估计。

        【讨论】:

        • 我试过了,一切(UTF-16-BE、LE、ansi 和 utf8)都带回了 utf-8。 :
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-22
        • 1970-01-01
        相关资源
        最近更新 更多