如何判断文件在C#中是否是文本可读的

时间:2013-01-22 01:06:10

标签: c# file text encoding human-readable

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

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类型或文件编码有关。

4 个答案:

答案 0 :(得分:4)

没有通用的方法来计算存储在文件中的信息类型。

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

请注意,HTTP会按内容类型标题提供有关文件类型的一些提示,但文件系统上没有此类信息。

答案 1 :(得分:1)

有一些方法可以用来“最好地猜测”文件是否是文本文件。当然,你支持的编码越多,这就越难,特别是如果计划支持CJK(中文日语韩文)脚本。我们暂时从Encoding.AsciiEncoding.UTF-8开始。

幸运的是,大多数非文本文件(可执行文件图像)在其中包含大量不可解析的字符前几千字节。

你可以做的是拿一个文件并扫描前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;
  }
}

答案 2 :(得分:0)

一种hacky方法是查看文件是否包含任何不是白色空间形式的下控制字符(0-31)(回车,制表符,垂直制表符,换行符,以及安全无效和文本结束)。如果是,那么它可能是二进制的。如果没有,可能不是。我没有做任何测试或任何事情,看看将这个规则应用于非ASCII编码时会发生什么,所以你必须自己进一步调查:)

答案 3 :(得分:0)

我的方法基于@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
                );
        }
    }