Как фильтровать каталог.Перечислять файлы с несколькими критериями?
у меня есть следующий код:
List<string> result = new List<string>();
foreach (string file in Directory.EnumerateFiles(path,"*.*",
SearchOption.AllDirectories)
.Where(s => s.EndsWith(".mp3") || s.EndsWith(".wma")))
{
result.Add(file);
}
Он отлично работает и делает то, что мне нужно. За исключением одной мелочи. Я хотел бы найти лучший способ фильтрации по нескольким расширениями. Я хотел бы использовать строковый массив с фильтрами, такими как это:
string[] extensions = { "*.mp3", "*.wma", "*.mp4", "*.wav" };
каков наиболее эффективный способ сделать это с помощью NET Framework 4.0/LINQ? Есть предложения?
Я был бы признателен за любую помощь в качестве случайного программиста : -)
7 ответов:
Я создал некоторые вспомогательные методы, чтобы решить эту проблему, которую я блоге ранее в этом году.
одна версия принимает шаблон регулярных выражений
\.mp3|\.mp4
, а другой строковый список и работает параллельно.public static class MyDirectory { // Regex version public static IEnumerable<string> GetFiles(string path, string searchPatternExpression = "", SearchOption searchOption = SearchOption.TopDirectoryOnly) { Regex reSearchPattern = new Regex(searchPatternExpression, RegexOptions.IgnoreCase); return Directory.EnumerateFiles(path, "*", searchOption) .Where(file => reSearchPattern.IsMatch(Path.GetExtension(file))); } // Takes same patterns, and executes in parallel public static IEnumerable<string> GetFiles(string path, string[] searchPatterns, SearchOption searchOption = SearchOption.TopDirectoryOnly) { return searchPatterns.AsParallel() .SelectMany(searchPattern => Directory.EnumerateFiles(path, searchPattern, searchOption)); } }
лишенный контекста LINQ, это сводится к тому, как узнать, соответствует ли файл списку расширений.
System.IO.Path.GetExtension()
лучше здесь, чемString.EndsWith()
. Несколько||
можно заменить на.Contains()
или.IndexOf()
в зависимости от коллекции.var extensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".mp3", ".wma", ".mp4", ".wav" }; ... s => extensions.Contains(Path.GetExtension(s))
string path = "C:\"; var result = new List<string>(); string[] extensions = { ".mp3", ".wma", ".mp4", ".wav" }; foreach (string file in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories) .Where(s => extensions.Any(ext => ext == Path.GetExtension(s)))) { result.Add(file); Console.WriteLine(file); }
самый элегантный подход, вероятно:
var directory = new DirectoryInfo(path); var masks = new[] { "*.mp3", "*.wav" }; var files = masks.SelectMany(directory.EnumerateFiles);
но это может быть не самым эффективным.
Как я отметил в комментарии, в то время как вспомогательные методы Микаэля Свенсона-отличные маленькие решения, если вы когда-либо пытаетесь сделать что-то для одноразового проекта в спешке снова, рассмотрите расширение Linq .Union (). Это позволяет объединить две перечислимые последовательности. В вашем случае код будет выглядеть так:
List<string> result = Directory.EnumerateFiles(path,"*.mp3", SearchOption.AllDirectories) .Union(Directory.EnumerateFiles(path, ".wma", SearchOption.AllDirectories)).ToList();
это создает и заполняет список результатов все в одной строке.
Я знаю, что это старый пост, но я придумал решение, которое люди хотели бы использовать.
private IEnumerable<FileInfo> FindFiles() { DirectoryInfo sourceDirectory = new DirectoryInfo(@"C:\temp\mydirectory"); string foldersFilter = "*bin*,*obj*"; string fileTypesFilter = "*.mp3,*.wma,*.mp4,*.wav"; // filter by folder name and extension IEnumerable<DirectoryInfo> directories = foldersFilter.Split(',').SelectMany(pattern => sourceDirectory.EnumerateDirectories(pattern, SearchOption.AllDirectories)); List<FileInfo> files = new List<FileInfo>(); files.AddRange(directories.SelectMany(dir => fileTypesFilter.Split(',').SelectMany(pattern => dir.EnumerateFiles(pattern, SearchOption.AllDirectories)))); // Pick up root files files.AddRange(fileTypesFilter.Split(',').SelectMany(pattern => sourceDirectory.EnumerateFiles(fileTypesFilter, SearchOption.TopDirectoryOnly))); // filter just by extension IEnumerable<FileInfo> files2 = fileTypesFilter.Split(',').SelectMany(pattern => sourceDirectory.EnumerateFiles(pattern, SearchOption.AllDirectories)); }
для фильтрации с использованием тех же строк списка расширений файлов, что и GUI, откройте диалоги, например:
".exe,.pdb".Split(',', ';', '|').SelectMany(_ => Directory.EnumerateFiles(".", "*" + _, searchOptions)
упаковано:
public static IEnumerable<string> EnumerateFilesFilter(string path, string filesFilter, SearchOption searchOption = SearchOption.TopDirectoryOnly) { return filesFilter.Split(',', ';', '|').SelectMany(_ => Directory.EnumerateFiles(path, "*" + _, searchOption)); }