使用枚举和 Lambda 筛选文件列表并删除不需要的扩展名

本文关键字:删除 不需要 扩展名 列表 文件 枚举 Lambda 筛选 | 更新日期: 2023-09-27 18:28:33

我正在使用此代码

       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()尝试访问引发权限错误的文件的异常的问题。

使用枚举和 Lambda 筛选文件列表并删除不需要的扩展名

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

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

请注意,这将导致此时立即遍历整个枚举。 但是,它只会完成一次。

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

  • 你提到有些图像你忽略了。 我会在点击磁盘以获取有关它们的信息之前过滤掉它们。 点击磁盘比检查路径名要昂贵得多
  • 将磁盘移动到后台线程

我同意 JaredPar 的观点,你要确保你不会重新枚举。 您的退货应带有 .ToList((,但var files = top_directory.EnumerateFiles(file_pattern);也需要它。

异常处理成本很高,因此不建议添加比现有内容更多的异常处理。 枚举文件不支持您要查找的过滤类型,因此您最终将不得不在某个地方手动执行此操作,最好这样做:

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

如果您仍然遇到性能问题,则必须考虑将操作分解为较小块的方法:如果文件名可靠,则可以提出一个方案来更改EnumerateFiles模式(所有文件都以"a"开头,然后是"b",然后是"c"等(。 或者,如果同一文件夹中有很多垃圾,是否可以更改目录结构,以便不需要的文件始终位于您知道要忽略的子文件夹中?