2

我正在使用此代码

       private IEnumerable<String> FindAccessableFiles(string path, string file_pattern, bool recurse)
    {
        IEnumerable<String> emptyList = new string[0];

        if (File.Exists(path))
            return new string[] { path };

        if (!Directory.Exists(path))
            return emptyList;

        var top_directory = new DirectoryInfo(path);

        // Enumerate the files just in the top directory.
        var files = top_directory.EnumerateFiles(file_pattern);
        var filesLength = files.Count();
        var filesList = Enumerable
                  .Range(0, filesLength)
                  .Select(i =>
                  {
                      string filename = null;
                      try
                      {
                          var file = files.ElementAt(i);
                          filename = file.FullName;                              
                      }
                      catch (UnauthorizedAccessException)
                      {
                      }
                      catch (InvalidOperationException)
                      {
                          // ran out of entries
                      }
                      return filename;
                  })
                  .Where(i => null != i);

        if (!recurse)
            return filesList;

        var dirs = top_directory.EnumerateDirectories("*");
        var dirsLength = dirs.Count();
        var dirsList = Enumerable
            .Range(0, dirsLength)
            .SelectMany(i =>
            {
                string dirname = null;
                try
                {
                    var dir = dirs.ElementAt(i);
                    dirname = dir.FullName;
                    return FindAccessableFiles(dirname, file_pattern, recurse);
                }
                catch (UnauthorizedAccessException)
                {
                }
                catch (InvalidOperationException)
                {
                    // ran out of entries
                }

                return emptyList;
            });
        return Enumerable.Concat(filesList, dirsList);
    }

我在遍历包含 100k+ 个文件的文件夹时遇到了一些性能问题——我在枚举它们时忽略了所有图像。

我正在尝试弄清楚如何将它们从枚举列表中排除,以便它们从一开始就不会被处理,但无法弄清楚如何去做。

我有一个List<String>我想排除的扩展名,并在代码中使用Contains.

如果我首先将它们排除在外,我会获得性能提升FindAccessableFiles吗?我该怎么做?如果文件扩展名包含在扩展名列表中,我最初的尝试是抛出异常,但我确信这不是最好的方法。

的目的FindAccessableFiles是生成一个文件列表,以规避在GetFiles()尝试访问引发权限错误的文件时引发异常的问题。

4

2 回答 2

2

部分问题在于FindAccessableFiles返回的IEnumerable<string>实例将在每次枚举时重新遍历整个目录结构。每次遍历枚举时都会重新评估SelectandWhere子句,因此您会多次重复这项昂贵的工作。.ToList对此的一种快速解决方法是通过调用返回值来强制步行一次

return Enumerable.Concat(filesList, dirsList).ToList();

请注意,这将导致此时整个枚举都被迅速遍历。但是,它只会执行一次。

如果您仍然看到性能问题,您应该考虑其他一些选项

  • 你提到有你忽略的图像。我会在点击磁盘以获取有关它们的信息之前将它们过滤掉。与检查路径名相比,访问磁盘的成本要高得多
  • 将磁盘行走移动到后台线程
于 2013-08-21T14:50:57.907 回答
1

我同意 JaredPar,您要确保不要重新枚举。您的回报应该有一个 .ToList(),但也var files = top_directory.EnumerateFiles(file_pattern);需要它。

异常处理是昂贵的,因此不建议添加超过你所拥有的。枚举文件不支持您正在寻找的过滤类型,因此您最终不得不在某处手动进行,最好这样做:

filename = excludedExtensionList.Any(e => e == file.Extension) ? null : file.FullName;

如果你仍然有性能问题,你必须考虑如何将操作分解成更小的块:如果文件名可靠,你可能会想出一个方案来改变你的 EnumerateFiles 模式(所有以“a”开头的文件,然后是“b”,然后是“c”等)。或者,如果有很多垃圾都放在同一个文件夹中,是否可以更改目录结构以使不需要的文件始终位于您知道可以忽略的子文件夹中?

于 2013-08-21T15:46:19.513 回答