Ich habe folgenden Code:
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);
}
Es funktioniert gut und macht was ich brauche. Bis auf eine kleine Sache. Ich möchte einen besseren Weg finden, um nach mehreren Erweiterungen zu filtern. Ich möchte ein String-Array mit Filtern wie diesem verwenden:
string[] extensions = { "*.mp3", "*.wma", "*.mp4", "*.wav" };
Was ist der effizienteste Weg, dies mit NET Framework 4.0 / LINQ zu tun? Irgendwelche Vorschläge?
Ich würde mich über jede Hilfe als gelegentlicher Programmierer freuen :-)
Antworten:
Ich habe einige Hilfsmethoden entwickelt, um dieses Problem zu lösen, über die ich Anfang dieses Jahres gebloggt habe .
Eine Version verwendet ein Regex-Muster
\.mp3|\.mp4
und die andere eine Zeichenfolgenliste und wird parallel ausgeführt.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)); } }
quelle
PARALLEL
Um nur einige Merkmale jeder der beiden Methoden zu nennen ... Bei der Methode wird bei der Suche NICHT zwischen Groß- und Kleinschreibung unterschieden, und die Ergebnisse, die Sie erhalten, sind nicht in Ordnung. Bei dieserREGEX
Methode wird bei der Suche zwischen Groß- und Kleinschreibung unterschieden (es sei denn, Sie verwenden etwas Ähnliches"(?i)\.mp3$|\.mp4$"
), und die Ergebnisse, die Sie erhalten, sind in der erwarteten Reihenfolge. Ich habe Tests durchgeführt und festgestellt, dass die parallele Version möglicherweise etwas leichter läuft, aber insgesamt ein SEHR kleiner Unterschied.Aus dem LINQ-Kontext entfernt, müssen Sie herausfinden, ob eine Datei mit einer Liste von Erweiterungen übereinstimmt.
System.IO.Path.GetExtension()
ist hier eine bessere Wahl alsString.EndsWith()
. Das Vielfache||
kann durch.Contains()
oder.IndexOf()
abhängig von der Sammlung ersetzt werden.var extensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".mp3", ".wma", ".mp4", ".wav" }; ... s => extensions.Contains(Path.GetExtension(s))
quelle
*
s entfernen, wenn Sie Zeichenfolgenvergleiche mit ihnen durchführen möchten.Der eleganteste Ansatz ist wahrscheinlich:
var directory = new DirectoryInfo(path); var masks = new[] { "*.mp3", "*.wav" }; var files = masks.SelectMany(directory.EnumerateFiles);
Aber es ist vielleicht nicht das effizienteste.
quelle
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); }
quelle
Wie ich in einem Kommentar bemerkte, sind die Hilfsmethoden von Mikael Svenson zwar großartige kleine Lösungen, aber wenn Sie jemals wieder versuchen, in Eile etwas für ein einmaliges Projekt zu tun, sollten Sie die Linq-Erweiterung .Union () in Betracht ziehen . Auf diese Weise können Sie zwei aufzählbare Sequenzen zusammenfügen. In Ihrem Fall würde der Code folgendermaßen aussehen:
List<string> result = Directory.EnumerateFiles(path,"*.mp3", SearchOption.AllDirectories) .Union(Directory.EnumerateFiles(path, ".wma", SearchOption.AllDirectories)).ToList();
Dadurch wird Ihre Ergebnisliste in einer Zeile erstellt und gefüllt.
quelle
Ich weiß, dass dies ein alter Beitrag ist, aber ich habe eine Lösung gefunden, die die Leute vielleicht gerne verwenden würden.
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)); }
quelle
Zum Filtern mit denselben Dateierweiterungen Listenzeichenfolgen wie GUI Open Dialogs, z.
".exe,.pdb".Split(',', ';', '|').SelectMany(_ => Directory.EnumerateFiles(".", "*" + _, searchOptions)
Verpackt:
public static IEnumerable<string> EnumerateFilesFilter(string path, string filesFilter, SearchOption searchOption = SearchOption.TopDirectoryOnly) { return filesFilter.Split(',', ';', '|').SelectMany(_ => Directory.EnumerateFiles(path, "*" + _, searchOption)); }
quelle
Ich habe dieses Problem folgendermaßen gelöst:
string[] formats = {".mp3", ".wma", ".mp4"}; foreach (var file in Directory.EnumerateFiles(folder, "*.*", SearchOption.AllDirectories).Where(x => formats.Any(x.EndsWith))) { // TODO... }
quelle