Come filtrare Directory.EnumerateFiles con più criteri?

Ho il codice seguente:

List result = new List(); foreach (string file in Directory.EnumerateFiles(path,"*.*", SearchOption.AllDirectories) .Where(s => s.EndsWith(".mp3") || s.EndsWith(".wma"))) { result.Add(file); } 

Funziona bene e fa quello che mi serve. Tranne per una piccola cosa. Mi piacerebbe trovare un modo migliore per filtrare su più estensioni. Vorrei usare un array di stringhe con filtri come questo:

 string[] extensions = { "*.mp3", "*.wma", "*.mp4", "*.wav" }; 

Qual è il modo più efficiente per farlo utilizzando NET Framework 4.0 / LINQ? Eventuali suggerimenti?

Apprezzerei qualsiasi aiuto essendo un programmatore occasionale 🙂

Ho creato alcuni metodi di supporto per risolvere questo problema che ho scritto all’inizio di quest’anno.

Una versione prende un modello regex \.mp3|\.mp4 e l’altro un elenco di stringhe e viene eseguito in parallelo.

 public static class MyDirectory { // Regex version public static IEnumerable 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 GetFiles(string path, string[] searchPatterns, SearchOption searchOption = SearchOption.TopDirectoryOnly) { return searchPatterns.AsParallel() .SelectMany(searchPattern => Directory.EnumerateFiles(path, searchPattern, searchOption)); } } 

Stripped dal contesto LINQ, questo dipende da come scoprire se un file corrisponde a un elenco di estensioni. System.IO.Path.GetExtension() è una scelta migliore qui di String.EndsWith() . Il multiplo || può essere sostituito con .Contains() o .IndexOf() seconda della collezione.

 var extensions = new HashSet(StringComparer.OrdinalIgnoreCase) { ".mp3", ".wma", ".mp4", ".wav" }; ... s => extensions.Contains(Path.GetExtension(s)) 
 string path = "C:\\"; var result = new List(); 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); } 

Come ho notato in un commento, mentre i metodi di aiuto di Mikael Svenson sono grandi piccole soluzioni, se si sta tentando di fare qualcosa per un progetto una tantum in fretta, si consideri l’estensione Linq .Union () . Questo ti permette di unire insieme due sequenze enumerabili. Nel tuo caso, il codice sarebbe simile a questo:

 List result = Directory.EnumerateFiles(path,"*.mp3", SearchOption.AllDirectories) .Union(Directory.EnumerateFiles(path, ".wma", SearchOption.AllDirectories)).ToList(); 

Questo crea e riempie l’elenco dei risultati tutto in una riga.

L’approccio più elegante è probabilmente:

 var directory = new DirectoryInfo(path); var masks = new[] { "*.mp3", "*.wav" }; var files = masks.SelectMany(directory.EnumerateFiles); 

Ma potrebbe non essere il più efficiente.

So che questo è un vecchio post, ma mi è venuta in mente una soluzione che le persone potrebbero voler usare.

 private IEnumerable 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 directories = foldersFilter.Split(',').SelectMany(pattern => sourceDirectory.EnumerateDirectories(pattern, SearchOption.AllDirectories)); List files = new List(); 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 files2 = fileTypesFilter.Split(',').SelectMany(pattern => sourceDirectory.EnumerateFiles(pattern, SearchOption.AllDirectories)); } 

Per il filtraggio utilizzando le stesse stringhe dell’elenco di estensioni file come windows di dialogo aperte della GUI, ad esempio:

 ".exe,.pdb".Split(',', ';', '|').SelectMany(_ => Directory.EnumerateFiles(".", "*" + _, searchOptions) 

Confezionato:

  public static IEnumerable EnumerateFilesFilter(string path, string filesFilter, SearchOption searchOption = SearchOption.TopDirectoryOnly) { return filesFilter.Split(',', ';', '|').SelectMany(_ => Directory.EnumerateFiles(path, "*" + _, searchOption)); }