【问题标题】:How to tell if a file is text-readable in C#如何判断文件是否在 C# 中是文本可读的
【发布时间】:2013-01-22 01:06:10
【问题描述】:

我正在做的项目列表的一部分是一个小文本编辑器。

At one point, you can load all the sub directories and files in a given directory. 程序会将每个节点添加为 TreeView 中的一个节点。

我想要的功能是只添加普通文本阅读器可读的文件。

此代码当前将其添加到树中:

TreeNode navNode = new TreeNode();
navNode.Text = file.Name;
navNode.Tag = file.FullName;

 directoryNode.Nodes.Add(navNode);

我知道我可以轻松地创建一个 if 语句,例如:

if(file.extension.equals(".txt"))

但我必须扩展该语句以包含它可能的每一个扩展。

有没有更简单的方法来做到这一点?我认为这可能与 mime 类型或文件编码有关。

【问题讨论】:

  • 这取决于“普通文本编辑器可读”的含义。一旦你确定了这一点,你的道路就会更加清晰。例如:仅包含 ASCII 字符是正确编码的 UTF-8 文件,仅包含可打印字符
  • 我会说只包含 ASCII 字符,我可以从那里移动。
  • 没有 100% 的方法.. 最好的方法是扩展和对前约 1024 个字节的数据进行采样,看看它是否满足您的需求。
  • Simon 说的差不多。要验证 ASCII 编码,您可以过滤掉大于 0x7F 的字节和那些表示控制字符的字节,但这在大文件上会很慢(您将遍历每个字节)。最好使用一些启发式方法,比如只查看文件的前几千字节。小心限制自己使用 ASCII - Unicode 现在非常流行,你会在最不期望的地方找到非 ASCII 的东西。不要为 UTF-8 滚动你自己的等价物——这太难了。使用 .NET 的内置内容 - 从 System.Char 开始。
  • 我会试着玩弄一些东西。谢谢!

标签: c# file text encoding human-readable


【解决方案1】:

没有确定文件中存储信息类型的通用方法。

即使您事先知道它是某种文本,如果您不知道创建文件使用什么编码,您也可能无法正确加载它。

请注意,HTTP 会通过 content-type 标头为您提供一些关于文件类型的提示,但文件系统上没有此类信息。

【讨论】:

  • 正如我上面所说,我想我必须选择 ASCII 或 UTF-8 文件。
【解决方案2】:

您可以使用几种方法来“最佳猜测”文件是否为文本文件。当然,您支持的编码越多,这就越难,特别是如果计划支持 CJK(ChineseJapaneseKorean)脚本。让我们先从Encoding.AsciiEncoding.UTF-8 开始吧。

幸运的是,大多数非文本文件(executablesimages等等)在它们的前几个千字节。

您可以做的是获取一个文件并扫描前 1-4KB(由您决定),看看是否出现任何“不可打印”字符。此操作不会花费太多时间,并且至少可以让您确定文件的内容。

public static async Task<bool> IsValidTextFileAsync(string path,
                                                    int scanLength = 4096)
{
  using(var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
  using(var reader = new StreamReader(stream, Encoding.UTF8))
  {
    var bufferLength = (int)Math.Min(scanLength, stream.Length);
    var buffer = new char[bufferLength];

    var bytesRead = await reader.ReadBlockAsync(buffer, 0, bufferLength);
    reader.Close();

    if(bytesRead != bufferLength)
      throw new IOException("There was an error reading from the file.");

    for(int i = 0; i < bytesRead; i++)
    {
      var c = buffer[i];

      if(char.IsControl(c))
        return false;
    }

    return true;
  }
}

【讨论】:

  • 小文件没有异步和扫描长度:public static bool IsValidTextFile(string path) { using (var stream = System.IO.File.Open(path, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)) using (var reader = new System.IO.StreamReader(stream, System.Text.Encoding.UTF8)) { var bytesRead = reader.ReadToEnd(); reader.Close(); return bytesRead.All(c =&gt; !char.IsControl(c)); } }
【解决方案3】:

我的方法基于@Rubenisme 的评论和@Erik 的回答。

    public static bool IsValidTextFile(string path)
    {
        using (var stream = System.IO.File.Open(path, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read))
        using (var reader = new System.IO.StreamReader(stream, System.Text.Encoding.UTF8)) 
        {
            var bytesRead = reader.ReadToEnd();
            reader.Close();
            return bytesRead.All(c => // Are all the characters either a:
                c == (char)10  // New line
                || c == (char)13 // Carriage Return
                || c == (char)11 // Tab
                || !char.IsControl(c) // Non-control (regular) character
                );
        }
    }

【讨论】:

    【解决方案4】:

    执行此操作的一个 hacky 方法是查看文件是否包含任何不是空格形式的低位控制字符 (0-31)(回车、制表符、垂直制表符、换行符等等)是安全的 null 和文本的结尾)。如果是这样,那么它可能是二进制的。如果没有,它可能不是。我没有做任何测试或任何事情来看看将这个规则应用于非 ASCII 编码时会发生什么,所以你必须自己进一步调查:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-09
      • 2015-11-15
      • 2011-07-14
      • 1970-01-01
      • 2020-09-18
      • 2015-03-21
      相关资源
      最近更新 更多