web-dev-qa-db-de.com

Können Sie Directory.GetFiles () mit mehreren Filtern aufrufen?

Ich versuche, die Directory.GetFiles()-Methode zu verwenden, um eine Liste von Dateien verschiedener Typen abzurufen, beispielsweise mp3s und jpg. Ich habe beide ohne Glück versucht:

Directory.GetFiles("C:\\path", "*.mp3|*.jpg", SearchOption.AllDirectories);
Directory.GetFiles("C:\\path", "*.mp3;*.jpg", SearchOption.AllDirectories);

Gibt es eine Möglichkeit, dies in einem Anruf zu tun?

310
Jason Z

Für .NET 4.0 und höher 

var files = Directory.EnumerateFiles("C:\\path", "*.*", SearchOption.AllDirectories)
            .Where(s => s.EndsWith(".mp3") || s.EndsWith(".jpg"));

Für frühere Versionen von .NET

var files = Directory.GetFiles("C:\\path", "*.*", SearchOption.AllDirectories)
            .Where(s => s.EndsWith(".mp3") || s.EndsWith(".jpg"));

edit: _ ​​Bitte lesen Sie die Kommentare. Die Verbesserung, die Paul Farry vorschlägt, und das Gedächtnis-/Leistungsproblem, auf das Christian.K weist, sind beide sehr wichtig.

458

Wie wäre es damit:

private static string[] GetFiles(string sourceFolder, string filters, System.IO.SearchOption searchOption)
{
   return filters.Split('|').SelectMany(filter => System.IO.Directory.GetFiles(sourceFolder, filter, searchOption)).ToArray();
}

Ich habe es hier (in den Kommentaren) gefunden: http://msdn.Microsoft.com/en-us/library/wz42302f.aspx

52
Albert

Wenn Sie eine große Liste von Erweiterungen zur Prüfung haben, können Sie Folgendes verwenden. Ich wollte nicht viele OR -Anweisungen erstellen, also änderte ich, was Lette schrieb.

string supportedExtensions = "*.jpg,*.gif,*.png,*.bmp,*.jpe,*.jpeg,*.wmf,*.emf,*.xbm,*.ico,*.eps,*.tif,*.tiff,*.g01,*.g02,*.g03,*.g04,*.g05,*.g06,*.g07,*.g08";
foreach (string imageFile in Directory.GetFiles(_tempDirectory, "*.*", SearchOption.AllDirectories).Where(s => supportedExtensions.Contains(Path.GetExtension(s).ToLower())))
{
    //do work here
}
29
jnoreiga

for

var exts = new[] { "mp3", "jpg" };

Du könntest:

public IEnumerable<string> FilterFiles(string path, params string[] exts) {
    return
        Directory
        .EnumerateFiles(path, "*.*")
        .Where(file => exts.Any(x => file.EndsWith(x, StringComparison.OrdinalIgnoreCase)));
}

Der wahre Vorteil von EnumerateFiles zeigt sich jedoch, wenn Sie die Filter aufteilen und die Ergebnisse zusammenführen:

public IEnumerable<string> FilterFiles(string path, params string[] exts) {
    return 
        exts.Select(x => "*." + x) // turn into globs
        .SelectMany(x => 
            Directory.EnumerateFiles(path, x)
            );
}

Es wird etwas schneller, wenn Sie sie nicht in Globs umwandeln müssen (d. H. exts = new[] {"*.mp3", "*.jpg"} bereits).

Leistungsbewertung basierend auf dem folgenden LinqPad-Test (Hinweis: Perf wiederholt den Delegierten nur 10000-mal) https://Gist.github.com/zaus/7454021

(erneut veröffentlicht und erweitert von 'duplicate', da diese Frage ausdrücklich keine LINQ angefordert hat: Mehrere Dateierweiterungen searchPattern für System.IO.Directory.GetFiles )

26
drzaus

Ich weiß, es ist eine alte Frage, aber LINQ: (.NET40 +)

var files = Directory.GetFiles("path_to_files").Where(file => Regex.IsMatch(file, @"^.+\.(wav|mp3|txt)$"));
14
Icehunter

Eine andere Möglichkeit, Linq zu verwenden, ohne dabei alles zurückgeben und filtern zu müssen.

var files = Directory.GetFiles("C:\\path", "*.mp3", SearchOption.AllDirectories).Union(Directory.GetFiles("C:\\path", "*.jpg", SearchOption.AllDirectories));

Es sind eigentlich zwei Aufrufe von GetFiles(), aber ich denke, es entspricht dem Geist der Frage und gibt sie in einer Liste wieder.

11
Dave Rael

Es gibt auch eine Descent-Lösung, die anscheinend keinen Speicher- oder Performance-Overhead aufweist und recht elegant ist:

string[] filters = new[]{"*.jpg", "*.png", "*.gif"};
string[] filePaths = filters.SelectMany(f => Directory.GetFiles(basePath, f)).ToArray();
9
Bas1l

Nee. Versuche Folgendes:

List<string> _searchPatternList = new List<string>();
    ...
    List<string> fileList = new List<string>();
    foreach ( string ext in _searchPatternList )
    {
        foreach ( string subFile in Directory.GetFiles( folderName, ext  )
        {
            fileList.Add( subFile );
        }
    }

    // Sort alpabetically
    fileList.Sort();

    // Add files to the file browser control    
    foreach ( string fileName in fileList )
    {
        ...;
    }

Entnommen aus: http://blogs.msdn.com/markda/archive/2006/04/20/580075.aspx

7
NotMe

Lassen

var set = new HashSet<string> { ".mp3", ".jpg" };

Dann

Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
         .Where(f => set.Contains(
             new FileInfo(f).Extension,
             StringComparer.OrdinalIgnoreCase));

oder

from file in Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
from ext in set
where String.Equals(ext, new FileInfo(file).Extension, StringComparison.OrdinalIgnoreCase)
select file;
6
abatishchev

Ich kann die .Where-Methode nicht verwenden, da ich in .NET Framework 2.0 programmiere (Linq wird nur in .NET Framework 3.5 und höher unterstützt). 

Bei dem folgenden Code wird die Groß- und Kleinschreibung nicht berücksichtigt (daher werden auch .CaB oder .cab aufgeführt).

string[] ext = new string[2] { "*.CAB", "*.MSU" };

foreach (string found in ext)
{
    string[] extracted = Directory.GetFiles("C:\\test", found, System.IO.SearchOption.AllDirectories);

    foreach (string file in extracted)
    {
        Console.WriteLine(file);
    }
}
5
jaysponsored

Die folgende Funktion sucht nach mehreren durch Kommas getrennten Mustern. Sie können auch einen Ausschluss angeben, zB: "! Web.config" sucht nach allen Dateien und schließt "web.config" aus. Muster können gemischt werden.

private string[] FindFiles(string directory, string filters, SearchOption searchOption)
{
    if (!Directory.Exists(directory)) return new string[] { };

    var include = (from filter in filters.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) where !string.IsNullOrEmpty(filter.Trim()) select filter.Trim());
    var exclude = (from filter in include where filter.Contains(@"!") select filter);

    include = include.Except(exclude);

    if (include.Count() == 0) include = new string[] { "*" };

    var rxfilters = from filter in exclude select string.Format("^{0}$", filter.Replace("!", "").Replace(".", @"\.").Replace("*", ".*").Replace("?", "."));
    Regex regex = new Regex(string.Join("|", rxfilters.ToArray()));

    List<Thread> workers = new List<Thread>();
    List<string> files = new List<string>();

    foreach (string filter in include)
    {
        Thread worker = new Thread(
            new ThreadStart(
                delegate
                {
                    string[] allfiles = Directory.GetFiles(directory, filter, searchOption);
                    if (exclude.Count() > 0)
                    {
                        lock (files)
                            files.AddRange(allfiles.Where(p => !regex.Match(p).Success));
                    }
                    else
                    {
                        lock (files)
                            files.AddRange(allfiles);
                    }
                }
            ));

        workers.Add(worker);

        worker.Start();
    }

    foreach (Thread worker in workers)
    {
        worker.Join();
    }

    return files.ToArray();

}

Verwendungszweck:

foreach (string file in FindFiles(@"D:\628.2.11", @"!*.config, !*.js", SearchOption.AllDirectories))
            {
                Console.WriteLine(file);
            }
4
Alexander Popov
List<string> FileList = new List<string>();
DirectoryInfo di = new DirectoryInfo("C:\\DirName");

IEnumerable<FileInfo> fileList = di.GetFiles("*.*");

//Create the query
IEnumerable<FileInfo> fileQuery = from file in fileList
                                  where (file.Extension.ToLower() == ".jpg" || file.Extension.ToLower() == ".png")
                                  orderby file.LastWriteTime
                                  select file;

foreach (System.IO.FileInfo fi in fileQuery)
{
    fi.Attributes = FileAttributes.Normal;
    FileList.Add(fi.FullName);
}

Ich habe gerade einen anderen Weg gefunden. Immer noch nicht eine Operation, aber werfen Sie es heraus, um zu sehen, was andere Leute darüber denken.

private void getFiles(string path)
{
    foreach (string s in Array.FindAll(Directory.GetFiles(path, "*", SearchOption.AllDirectories), predicate_FileMatch))
    {
        Debug.Print(s);
    }
}

private bool predicate_FileMatch(string fileName)
{
    if (fileName.EndsWith(".mp3"))
        return true;
    if (fileName.EndsWith(".jpg"))
        return true;
    return false;
}
3
Jason Z

Wie wäre es mit

string[] filesPNG = Directory.GetFiles(path, "*.png");
string[] filesJPG = Directory.GetFiles(path, "*.jpg");
string[] filesJPEG = Directory.GetFiles(path, "*.jpeg");

int totalArraySizeAll = filesPNG.Length + filesJPG.Length + filesJPEG.Length;
List<string> filesAll = new List<string>(totalArraySizeAll);
filesAll.AddRange(filesPNG);
filesAll.AddRange(filesJPG);
filesAll.AddRange(filesJPEG);
3
MattyMerrix
DirectoryInfo directory = new DirectoryInfo(Server.MapPath("~/Contents/"));

//Using Union

FileInfo[] files = directory.GetFiles("*.xlsx")
                            .Union(directory
                            .GetFiles("*.csv"))
                            .ToArray();
2
Nilesh Padhiyar
/// <summary>
/// Returns the names of files in a specified directories that match the specified patterns using LINQ
/// </summary>
/// <param name="srcDirs">The directories to seach</param>
/// <param name="searchPatterns">the list of search patterns</param>
/// <param name="searchOption"></param>
/// <returns>The list of files that match the specified pattern</returns>
public static string[] GetFilesUsingLINQ(string[] srcDirs,
     string[] searchPatterns,
     SearchOption searchOption = SearchOption.AllDirectories)
{
    var r = from dir in srcDirs
            from searchPattern in searchPatterns
            from f in Directory.GetFiles(dir, searchPattern, searchOption)
            select f;

    return r.ToArray();
}
2
A.Ramazani

Nop ... Ich glaube, Sie müssen so viele Anrufe tätigen, wie Sie möchten. 

Ich würde selbst eine Funktion erstellen, die ein Array auf Strings mit den benötigten Erweiterungen aufnimmt und dann dieses Array durchläuft und alle erforderlichen Aufrufe durchführt. Diese Funktion gibt eine generische Liste der Dateien zurück, die den von mir gesendeten Erweiterungen entsprechen.

Ich hoffe es hilft.

2
sebagomez

Erstellen Sie die gewünschten Erweiterungen, d. H. ".Mp3.jpg.wma.wmf", und prüfen Sie, ob jede Datei die gewünschte Erweiterung enthält.

string myExtensions=".jpg.mp3";

string[] files=System.IO.Directory.GetFiles("C:\myfolder");

foreach(string file in files)
{
   if(myExtensions.ToLower().contains(System.IO.Path.GetExtension(s).ToLower()))
   {
      //this file has passed, do something with this file

   }
}

Der Vorteil dieses Ansatzes ist, dass Sie Erweiterungen hinzufügen oder entfernen können, ohne den Code bearbeiten zu müssen, d. H. Um png-Bilder hinzuzufügen, schreiben Sie einfach myExtensions = ".

2
Evado

in .NET 2.0 (kein Linq):

public static List<string> GetFilez(string path, System.IO.SearchOption opt,  params string[] patterns)
{
    List<string> filez = new List<string>();
    foreach (string pattern in patterns)
    {
        filez.AddRange(
            System.IO.Directory.GetFiles(path, pattern, opt)
        );
    }


    // filez.Sort(); // Optional
    return filez; // Optional: .ToArray()
}

Dann benutze es:

foreach (string fn in GetFilez(path
                             , System.IO.SearchOption.AllDirectories
                             , "*.xml", "*.xml.rels", "*.rels"))
{}
2
Stefan Steiger

Ich frage mich, warum es so viele "Lösungen" gibt?

Wenn mein Anfänger-Verständnis über die Funktionsweise von GetFiles richtig ist, gibt es nur zwei Möglichkeiten. Jede der oben genannten Lösungen lässt sich auf diese zurückführen:

  1. GetFiles, dann filter: Schnell, aber ein Speicher-Killer durch Speichern von Overhead, bis die Filter angewendet werden

  2. Filtern während GetFiles: Je mehr Filter gesetzt werden, desto geringer ist der Speicherverbrauch, da kein Overhead gespeichert wird.
    Dies wird in einem der oben genannten Beiträge mit einem eindrucksvollen Benchmark erklärt: Jede Filteroption bewirkt einen separaten GetFile-Vorgang, so dass derselbe Teil der Festplatte mehrmals gelesen wird.

Meiner Meinung nach ist Option 1) besser, aber die Verwendung von SearchOption.AllDirectories für Ordner wie C:\würde sehr viel Speicherplatz beanspruchen.
Dazu würde ich einfach eine rekursive Untermethode erstellen, die alle Unterordner mit Option 1 durchläuft.

Dies sollte nur 1 GetFiles-Operation für jeden Ordner bewirken und daher schnell sein (Option 1). Es sollte jedoch nur wenig Speicherplatz verwendet werden, da die Filter nach dem Lesen jedes Unterordners angewendet werden.

Bitte korrigieren Sie mich, wenn ich falsch liege. Ich bin, wie gesagt, ziemlich neu in der Programmierung, möchte aber ein tieferes Verständnis der Dinge erlangen, um schließlich gut darin zu werden :)

1
Janis

Ich hatte das gleiche Problem und konnte die richtige Lösung nicht finden, also schrieb ich eine Funktion namens GetFiles:

/// <summary>
/// Get all files with a specific extension
/// </summary>
/// <param name="extensionsToCompare">string list of all the extensions</param>
/// <param name="Location">string of the location</param>
/// <returns>array of all the files with the specific extensions</returns>
public string[] GetFiles(List<string> extensionsToCompare, string Location)
{
    List<string> files = new List<string>();
    foreach (string file in Directory.GetFiles(Location))
    {
        if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.')+1).ToLower())) files.Add(file);
    }
    files.Sort();
    return files.ToArray();
}

Diese Funktion ruft Directory.Getfiles() nur einmal auf.

Rufen Sie zum Beispiel die Funktion wie folgt auf:

string[] images = GetFiles(new List<string>{"jpg", "png", "gif"}, "imageFolder");

BEARBEITEN: Um eine Datei mit mehreren Erweiterungen zu erhalten, verwenden Sie diese:

/// <summary>
    /// Get the file with a specific name and extension
    /// </summary>
    /// <param name="filename">the name of the file to find</param>
    /// <param name="extensionsToCompare">string list of all the extensions</param>
    /// <param name="Location">string of the location</param>
    /// <returns>file with the requested filename</returns>
    public string GetFile( string filename, List<string> extensionsToCompare, string Location)
    {
        foreach (string file in Directory.GetFiles(Location))
        {
            if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.') + 1).ToLower()) &&& file.Substring(Location.Length + 1, (file.IndexOf('.') - (Location.Length + 1))).ToLower() == filename) 
                return file;
        }
        return "";
    }

Rufen Sie zum Beispiel die Funktion wie folgt auf:

string image = GetFile("imagename", new List<string>{"jpg", "png", "gif"}, "imageFolder");
1
Quispie

Wenn Sie VB.NET verwenden (oder die Abhängigkeit in Ihr C # -Projekt importieren), gibt es tatsächlich eine praktische Methode, mit der Sie nach mehreren Erweiterungen filtern können:

Microsoft.VisualBasic.FileIO.FileSystem.GetFiles("C:\\path", Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, new string[] {"*.mp3", "*.jpg"});

In VB.NET kann über den My-Namespace darauf zugegriffen werden:

My.Computer.FileSystem.GetFiles("C:\path", FileIO.SearchOption.SearchAllSubDirectories, {"*.mp3", "*.jpg"})

Leider unterstützen diese Convenience-Methoden keine faul evaluierte Variante wie Directory.EnumerateFiles().

0
Crusha K. Rool

ich weiß nicht, welche Lösung besser ist, aber ich verwende das:

String[] ext = "*.ext1|*.ext2".Split('|');

            List<String> files = new List<String>();
            foreach (String tmp in ext)
            {
                files.AddRange(Directory.GetFiles(dir, tmp, SearchOption.AllDirectories));
            }
0
elle0087

Die Verwendung des GetFiles-Suchmusters zum Filtern der Erweiterung ist nicht sicher. Zum Beispiel haben Sie zwei Dateien Test1.xls und Test2.xlsx, und Sie möchten die xls-Datei mithilfe des Suchmusters * .xls herausfiltern. GetFiles gibt jedoch beide Test1 zurück. xls und Test2.xlsx Dies war mir nicht bewusst und in der Produktionsumgebung wurde ein Fehler angezeigt, als temporäre Dateien plötzlich als richtige Dateien behandelt wurden. Das Suchmuster lautete * .txt, und die temporären Dateien wurden mit * .txt20181028_100753898 .__ bezeichnet. Das Suchmuster kann daher nicht als vertrauenswürdig eingestuft werden. Daher müssen Sie auch die Dateinamen zusätzlich prüfen.

0
WillyS