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

时间:2012-12-21 16:15:51

标签: c# .net file-io

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

问题

  1. 是否有更快的方法(使用C#)?
  2. 是否有任何方案会因此代码而失败?
  3. 注意:我使用非常小的文件进行了测试。文件数量也很少。

    CODE

    static void Main()
        {
            string sourceFolder = @"C:\Test";
            string searchWord = ".class1";
    
            List<string> allFiles = new List<string>();
            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<string> 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. Using StreamReader to check if a file contains a string
    2. Splitting a String with two criteria
    3. C# detect folder junctions in a path
    4. Detect Symbolic Links, Junction Points, Mount Points and Hard Links
    5. FolderBrowserDialog SelectedPath with reparse points
    6. C# - High Quality Byte Array Conversion of Images

5 个答案:

答案 0 :(得分:26)

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

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

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

答案 1 :(得分:10)

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

  1. 使用Directory.EnumerateDirectories代替GetDirectories,它会立即返回IEnumerable,因此您无需等待它在处理之前完成所有目录的读取。
  2. 使用ReadLines代替ReadAllText,这只会在内存中一次加载一行,如果你点击一个大文件,这将是一个大问题。
  3. 如果您使用的是足够新版本的.NET,请使用Parallel.ForEach,这样您就可以一次搜索多个文件。
  4. 您可能无法打开文件,需要检查读取权限或add to the manifest您的程序需要管理员权限(您仍应检查)
  5. 我正在创建一个二进制搜索工具,这里有一些我写给你的手的片段

    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 search algorithm可以大大改善,但是我找不到二进制实现,而且我最初没有时间编写它来实现它。

答案 2 :(得分:3)

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

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

如果您按照此SO Post中的链接进行操作,则可能需要先实施索引。我没有按照链接,但值得一看。

只是抬头,这将是你当前方法的一个强烈转变,需要

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

答案 3 :(得分:1)

如果您缺少permission to open a file,我认为您的代码会失败并出现异常。

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

后一个代码支持

  1. 正则表达式搜索和
  2. 文件扩展名的过滤器
  3. - 你应该考虑的事情。

答案 4 :(得分:1)

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

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