如何高效合并多组Directory.EnumerateFiles查询获取最新指定文件
优化文件筛选逻辑:高效获取符合规则的最新文件
需求概述
从指定目录中获取3个符合特定规则的最新文件:
- 文件名包含"red"且不以"H"开头
- 文件名包含"red"且以"H"开头
- 文件名包含"blue"且不以"H"开头
当前代码可正常运行,但多次调用Directory.EnumerateFiles导致IO效率偏低,需优化实现方式。
当前可运行代码
string orderNum = "123465"; string[] s1 = Directory.EnumerateFiles(pathSetting, "*" + orderNum+ "*.txt", SearchOption.AllDirectories) .Where(name => name.Contains("red") && !name.StartsWith("H")) .OrderByDescending(file => new FileInfo(file).LastWriteTime) .ToArray(); string[] s2 = Directory.EnumerateFiles(pathSetting, "*" + orderNum+ "*.txt", SearchOption.AllDirectories) .Where(name => name.Contains("red") && name.StartsWith("H")) .OrderByDescending(file => new FileInfo(file).LastWriteTime) .ToArray(); string[] s3 = Directory.EnumerateFiles(pathSetting, "*" + orderNum+ "*.txt", SearchOption.AllDirectories) .Where(name => name.Contains("blue") && !name.StartsWith("H")) .OrderByDescending(file => new FileInfo(file).LastWriteTime) .ToArray(); int sourceArrayLength = (s1.Length > 0 ? 1 : 0) + (s2.Length > 0 ? 1 : 0) + (s3.Length > 0 ? 1 : 0); string[] sourceFiles = new string[sourceArrayLength]; int arrayCount = 0; if (s1.Length > 0) { sourceFiles[arrayCount] = s1[0]; arrayCount++; } if (s2.Length > 0) { sourceFiles[arrayCount] = s2[0]; arrayCount++; } if (s3.Length > 0) { sourceFiles[arrayCount] = s3[0]; arrayCount++; } // perform action on the files
尝试的错误代码及问题
string[] sFull = Directory.EnumerateFiles(pathSetting, "*" + orderNum+ "*.txt", SearchOption.AllDirectories) .First(name => name.Contains("red") && name.StartsWith("H")) .OrderByDescending(file => new FileInfo(file).LastWriteTime) .Concat(Directory.EnumerateFiles(pathSetting, "*" + orderNum+ "*.txt", SearchOption.AllDirectories) .First(name => name.Contains("red") && !name.StartsWith("H")) .OrderByDescending(file => new FileInfo(file).LastWriteTime)) .Concat(Directory.EnumerateFiles(pathSetting, "*" + orderNum+ "*.txt", SearchOption.AllDirectories) .First(name => name.Contains("blue") && !name.StartsWith("H")) .OrderByDescending(file => new FileInfo(file).LastWriteTime)) .ToArray();
错误原因:First()返回单个字符串而非可枚举集合,无法直接调用OrderByDescending,导致编译失败。
优化方案
核心思路:仅遍历目录一次,提前获取文件写入时间以避免重复IO操作,再按规则筛选各组最新文件。
优化代码
string orderNum = "123465"; var searchPattern = $"*{orderNum}*.txt"; // 一次性遍历目录,获取符合通配符的文件路径及写入时间 var allFiles = Directory.EnumerateFiles(pathSetting, searchPattern, SearchOption.AllDirectories) .Select(filePath => new { Path = filePath, LastWriteTime = File.GetLastWriteTime(filePath) // 静态方法更高效,无需创建FileInfo实例 }); // 定义三个筛选规则 var rules = new List<Func<(string Path, DateTime LastWriteTime), bool>> { f => f.Path.Contains("red") && !f.Path.StartsWith("H"), f => f.Path.Contains("red") && f.Path.StartsWith("H"), f => f.Path.Contains("blue") && !f.Path.StartsWith("H") }; // 收集每个规则下的最新文件 var sourceFiles = new List<string>(); foreach (var rule in rules) { var latestFile = allFiles.Where(rule) .OrderByDescending(f => f.LastWriteTime) .FirstOrDefault(); if (latestFile != null) { sourceFiles.Add(latestFile.Path); } } // 后续操作sourceFiles即可 // perform action on the files
优化点说明
- 减少IO次数:从3次目录遍历改为1次,大幅提升大目录场景下的效率。
- 降低资源消耗:用
File.GetLastWriteTime()替代重复创建FileInfo实例,减少内存占用。 - 逻辑简洁可维护:通过规则列表统一处理筛选逻辑,避免冗余代码。
- 异常安全:用
FirstOrDefault()替代First(),无匹配文件时不会抛出异常。
额外建议
- 若仅需文件名而非完整路径,可在
Select中使用Path.GetFileName(filePath)进一步减少内存占用。 - 针对超大型目录,可使用
Directory.EnumerateFilesAsync异步遍历,避免阻塞WebAPI主线程。
内容的提问来源于stack exchange,提问作者FatherOfDiwaffe
相关产品推荐
相关产品推荐

