我正在做的项目列表的一部分是一个小文本编辑器。
在某一点上,您可以加载给定目录中的所有子目录和文件。程序将把每个节点添加到TreeView中。
我想要的功能是只添加普通文本阅读器可读的文件。
下面的代码将它添加到树中:
TreeNode navNode = new TreeNode();
navNode.Text = file.Name;
navNode.Tag = file.FullName;
directoryNode.Nodes.Add(navNode);
我知道我可以很容易地创建一个if语句,像这样:
if(file.extension.equals(".txt"))
但是我必须扩展语句以包含所有可能的扩展名
有更简单的方法吗?我想这可能与mime类型或文件编码有关。
没有确定文件中存储的信息类型的通用方法。
即使你事先知道它是某种类型的文本,如果你不知道使用什么编码来创建文件,你可能无法正确加载它。
请注意,HTTP通过内容类型头给您一些关于文件类型的提示,但在文件系统中没有这样的信息。
您可以使用一些方法来"最佳猜测"该文件是否为文本文件。当然,您支持的编码越多,这就变得越困难,特别是如果计划支持CJK (中文、日文、韩文)脚本。我们先从Encoding.Ascii
和Encoding.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;
}
}
我的方法是基于@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
);
}
}
一种简单的方法是查看文件是否包含任何不是空白形式的较低控制字符(0-31)(回车、制表符、垂直制表符、换行,以及安全的null和文本结束)。如果是,那么它可能是二进制的。如果没有,很可能就不是。我没有做任何测试或任何事情,看看将此规则应用于非ASCII编码时会发生什么,所以您必须自己进一步调查:)