【问题标题】:C# - Check if File is Text BasedC# - 检查文件是否基于文本
【发布时间】:2011-06-12 07:22:27
【问题描述】:

如何测试我在 C# 中使用 FileStream 打开的文件是否是“文本类型”文件?我希望我的程序可以打开任何基于文本的文件,例如 .txt、.html 等。

但不能打开.doc或.pdf或.exe等文件。

【问题讨论】:

  • 创建一个TXT文件,重命名为myfile.abc,在你眼里还是“文本类型”的文件吗?
  • 是的。重要的是文件的内容,而不是扩展名。
  • 那么a.exe有可能是一个文本类型的文件(在你的程序中)?
  • 好吧,如果是txt文件,扩展名被修改了,那么理论上是可以的。
  • 查看这个解决方案filesignatures.codeplex.com

标签: c# file-io


【解决方案1】:

一般来说:没有办法说出来。

如果您使用 8 位编码打开以 UTF-16 存储的文本文件,它可能看起来像二进制文件。同样有人可以将文本文件保存为.doc(它是一个文档)。

虽然您可以打开文件并查看某些内容,但所有此类启发式方法有时会失败(例如,记事本尝试这样做,但通过仔细选择几个字符,记事本会猜错并显示完全不同的内容)。

如果你有一个特定的场景,而不是能够打开和处理任何东西,你应该能够做得更好。

【讨论】:

    【解决方案2】:

    我想你可以只检查前 1000 个(任意数字)字符,看看是否有不可打印的字符,或者它们是否都是特定范围内的 ascii。如果是后者,假设是文本?

    无论你做什么都是猜测。

    【讨论】:

    • 也许检查空格和换行符的定期间隔
    • 更新:如今,文本文件更可能是 UTF-8 或类似的 Unicode 字符编码。寻找更新的答案。例如,了解 Notepad++ 如何判断文件是文本。
    • 许多应用程序检查 NUL 字符以确定文件是否为二进制文件。 Git 就是一个例子。请参阅下面的完整答案。
    【解决方案3】:

    正如其他人指出的那样,没有绝对的方法可以确定。然而,为了确定一个文件是否是二进制文件(可以说这比确定它是否是文本文件更容易),一些实现会检查连续的 NUL 字符。 Git 显然只是检查前 8000 个字符是否有 NUL,如果找到,则将文件视为二进制文件。详情请见here

    这是我编写的一个类似的 C# 解决方案,它查找给定数量的必需连续 NUL。如果IsBinary 返回 false,那么您的文件很可能是基于文本的。

    public bool IsBinary(string filePath, int requiredConsecutiveNul = 1)
    {
        const int charsToCheck = 8000;
        const char nulChar = '\0';
    
        int nulCount = 0;
    
        using (var streamReader = new StreamReader(filePath))
        {
            for (var i = 0; i < charsToCheck; i++)
            {
                if (streamReader.EndOfStream)
                    return false;
    
                if ((char) streamReader.Read() == nulChar)
                {
                    nulCount++;
    
                    if (nulCount >= requiredConsecutiveNul)
                        return true;
                }
                else
                {
                    nulCount = 0;
                }
            }
        }
    
        return false;
    }
    

    【讨论】:

      【解决方案4】:

      要获得一个文件的真实类型,你必须检查它的标题,即使扩展名被修改也不会改变。您可以获取标题列表here,并在您的代码中使用类似这样的内容:

      using(var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
      {
         using(var reader = new BinaryReader(stream))
         {
           // read the first X bytes of the file
           // In this example I want to check if the file is a BMP
           // whose header is 424D in hex(2 bytes 6677)
           string code = reader.ReadByte().ToString() + reader.ReadByte().ToString();
           if (code.Equals("6677"))
           {
              //it's a BMP file
           }
         }
      }
      

      【讨论】:

      • 我对您指向“此处”的链接感兴趣,但它已损坏。你知道那个 URL 是什么,还是新的 URL 是什么??
      • @MacGyver: 抱歉,我无法控制损坏的链接。我在别人的帖子中遇到了这个解决方案。
      • 这种方法是有缺陷的。无法区分 BMP 文件和以字符“BM”开头的文件,这种情况很有可能发生。
      • 实际上,这应该扩展到检查前两个字符之外的多个字符,以确定文件缺少标题的“可能性”,并且实际上是某种其他格式。例如,如果您读取文件的所有字节,并且它们都没有设置符号位,那么它很可能是 ASCII 文本。确定它是否实际上是一个没有 BOM 的 UTF-8 文本文件要复杂得多(不可能做到完美)。
      【解决方案5】:

      我有一个适合我的解决方案。这是检查所有类型的二进制文件的通用解决方案。

           /// <summary>
           /// This method checks whether selected file is Binary file or not.
           /// </summary>     
           public bool CheckForBinary()
           {
      
                   Stream objStream = new FileStream("your file path", FileMode.Open, FileAccess.Read);
                   bool bFlag = true;
      
                   // Iterate through stream & check ASCII value of each byte.
                   for (int nPosition = 0; nPosition < objStream.Length; nPosition++)
                   {
                       int a = objStream.ReadByte();
      
                       if (!(a >= 0 && a <= 127))
                       {
                           break;            // Binary File
                       }
                       else if (objStream.Position == (objStream.Length))
                       {
                           bFlag = false;    // Text File
                       }
                   }
                   objStream.Dispose();
      
                   return bFlag;                   
           }
      

      【讨论】:

      • 当然这只适用于真正的ASCII。不适用于其他带有重音符号的字符
      【解决方案6】:
      public bool IsTextFile(string FilePath)
        using (StreamReader reader = new StreamReader(FilePath))
        {
             int Character;
             while ((Character = reader.Read()) != -1)
             {
                 if ((Character > 0 && Character < 8) || (Character > 13 && Character < 26))
                 {
                          return false; 
                 }
             }
        }
        return true;
      }
      

      【讨论】:

      • 解释你为什么选择你所做的范围。
      猜你喜欢
      • 1970-01-01
      • 2013-09-19
      • 2013-06-04
      • 2012-11-09
      • 2023-03-14
      • 2019-04-24
      • 2018-01-15
      • 1970-01-01
      • 2011-05-03
      相关资源
      最近更新 更多