更好用C#搜索所有文件中的字符串

在参考了很多博客和文章之后,我已经达到了以下代码,用于在文件夹内的所有文件中搜索字符串。 它在我的测试中运行良好。

质询

  1. 有没有更快的方法(使用C#)?
  2. 是否有任何方案会因此代码而失败?

注意:我测试了非常小的文件。 文件数量也很少。

static void Main() { string sourceFolder = @"C:\Test"; string searchWord = ".class1"; List allFiles = new List(); AddFileNamesToList(sourceFolder, allFiles); foreach (string fileName in allFiles) { string contents = File.ReadAllText(fileName); if (contents.Contains(searchWord)) { Console.WriteLine(fileName); } } Console.WriteLine(" "); System.Console.ReadKey(); } public static void AddFileNamesToList(string sourceDir, List allFiles) { string[] fileEntries = Directory.GetFiles(sourceDir); foreach (string fileName in fileEntries) { allFiles.Add(fileName); } //Recursion string[] subdirectoryEntries = Directory.GetDirectories(sourceDir); foreach (string item in subdirectoryEntries) { // Avoid "reparse points" if ((File.GetAttributes(item) & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint) { AddFileNamesToList(item, allFiles); } } } 

参考

  1. 使用StreamReader检查文件是否包含字符串
  2. 使用两个条件拆分字符串
  3. C#检测路径中的文件夹连接
  4. 检测符号链接,连接点,挂载点和硬链接
  5. FolderBrowserDialog具有重新分析点的SelectedPath
  6. C# – 图像的高质量字节数组转换

而不是File.ReadAllText()更好地使用

 File.ReadLines(@"C:\file.txt"); 

它返回IEnumerable (yielding),因此如果在到达文本文件的最后一行之前找到了字符串,则不必读取整个文件

我写的东西非常相似,我建议做一些改变。

  1. 使用Directory.EnumerateDirectories而不是GetDirectories,它会立即返回IEnumerable,因此您无需等待它在处理之前完成所有目录的读取。
  2. 使用ReadLines而不是ReadAllText,这只会在内存中一次加载一行,如果你点击一个大文件,这将是一个大问题。
  3. 如果您使用的是足够新版本的.NET,请使用Parallel.ForEach ,这样您就可以一次搜索多个文件。
  4. 您可能无法打开文件,需要检查读取权限或将清单添加到您的程序需要管理权限(您仍应检查)

我正在创建一个二进制搜索工具,这里有一些我写给你的手的片段

 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { Parallel.ForEach(Directory.EnumerateFiles(_folder, _filter, SearchOption.AllDirectories), Search); } //_array contains the binary pattern I am searching for. private void Search(string filePath) { if (Contains(filePath, _array)) { //filePath points at a match. } } private static bool Contains(string path, byte[] search) { //I am doing ReadAllBytes due to the fact that I am doing a binary search not a text search // There are no "Lines" to seperate out on. var file = File.ReadAllBytes(path); var result = Parallel.For(0, file.Length - search.Length, (i, loopState) => { if (file[i] == search[0]) { byte[] localCache = new byte[search.Length]; Array.Copy(file, i, localCache, 0, search.Length); if (Enumerable.SequenceEqual(localCache, search)) loopState.Stop(); } }); return result.IsCompleted == false; } 

这使用两个嵌套的并行循环。 这种设计非常低效,并且可以通过使用Booyer-Moore搜索算法大大改进,但我找不到二进制实现,而且我没有时间最初编写它来自己实现它。

这里的主要问题是您每次搜索都会实时搜索所有文件。 如果2个以上的用户同时搜索,则还存在文件访问冲突的可能性。

为了大幅度提高性能,我会提前索引文件,并在编辑/保存时进行索引。 使用类似lucene.net的东西存储索引,然后查询索引(再次使用luence.net )并将文件名返回给用户。 所以用户永远不会直接查询文件。

如果您按照此SOpost中的链接,您可能在实施索引方面有一个良好的开端。 我没有按照链接,但值得一看。

只是抬头,这将是你目前的方法的强烈转变,并将需要

  1. 监视/索引文件的服务
  2. UI项目

如果您缺少permission to open a file我认为您的代码将失败并出现exception。

将其与此处的代码进行比较: http : //bgrep.codeplex.com/releases/view/36186

后一个代码支持

  1. 正则表达式搜索和
  2. 文件扩展名的filter

– 你应该考虑的事情。

  1. 而不是Contains更好的使用算法Boyer-Moore搜索。

  2. 失败场景:文件没有读取权限。