使用枚举和 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()
尝试访问引发权限错误的文件的异常的问题。
部分问题在于FindAccessableFiles
返回一个IEnumerable<string>
实例,该实例将在每次枚举时重新遍历整个目录结构。 每次遍历枚举时,都会重新计算 Select
和 Where
子句,因此您会多次重复这项昂贵的工作。 对此的一个快速解决方法是通过对返回值调用 .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"等(。 或者,如果同一文件夹中有很多垃圾,是否可以更改目录结构,以便不需要的文件始终位于您知道要忽略的子文件夹中?