web-dev-qa-db-fra.com

Pouvez-vous appeler Directory.GetFiles () avec plusieurs filtres?

J'essaie d'utiliser la méthode Directory.GetFiles() pour récupérer une liste de fichiers de plusieurs types, tels que mp3 et jpg. J'ai essayé les deux choses suivantes sans succès:

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

Y a-t-il un moyen de faire cela en un seul appel?

310
Jason Z

Pour .NET 4.0 et versions ultérieures, 

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

Pour les versions antérieures de .NET,

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

edit: _ ​​Veuillez lire les commentaires. L'amélioration suggérée par Paul Farry et le problème de mémoire/de performances signalé par Christian.K sont très importants.

458

Que dis-tu de ça:

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();
}

Je l'ai trouvé ici (dans les commentaires): http://msdn.Microsoft.com/en-us/library/wz42302f.aspx

52
Albert

Si vous avez une longue liste d'extensions à vérifier, vous pouvez utiliser ce qui suit. Je ne voulais pas créer beaucoup d'instructions OR, j'ai donc modifié ce que Lette a écrit.

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" };

Vous pourriez:

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

Mais le véritable avantage de EnumerateFiles apparaît lorsque vous séparez les filtres et fusionnez les résultats:

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

Cela va un peu plus vite si vous n’avez pas à les transformer en globs (c'est-à-dire exts = new[] {"*.mp3", "*.jpg"} déjà).

Évaluation des performances basée sur le test LinqPad suivant (remarque: Perf répète simplement le délégué 10000 fois) https://Gist.github.com/zaus/7454021

(republié et étendu de 'dupliquer' puisque cette question demandait spécifiquement pas LINQ: Extensions de fichiers multiples searchPattern pour System.IO.Directory.GetFiles )

26
drzaus

Je sais que c'est une vieille question mais LINQ: (.NET40 +)

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

Une autre façon d'utiliser Linq, mais sans avoir à tout retourner et à filtrer cela en mémoire.

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

En fait, il s'agit de 2 appels à GetFiles(), mais je pense que cela correspond à l'esprit de la question et les renvoie dans un énumérable.

11
Dave Rael

Il existe également une solution de descente qui ne semble pas avoir de surcharge de mémoire ou de performances et qui est assez élégante

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

Nan. Essayez ce qui suit:

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 )
    {
        ...;
    }

Extrait de: http://blogs.msdn.com/markda/archive/2006/04/20/580075.aspx

7
NotMe

Laisser

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

Ensuite

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

ou

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

Je ne peux pas utiliser la méthode .Where car je programme dans .NET Framework 2.0 (Linq n'est pris en charge que dans .NET Framework 3.5+). 

Le code ci-dessous n'est pas sensible à la casse (donc .CaB ou .cab sera aussi répertorié).

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

La fonction suivante recherche sur plusieurs modèles, séparés par des virgules. Vous pouvez également spécifier une exclusion, par exemple: "! Web.config" recherchera tous les fichiers et exclura "web.config". Les motifs peuvent être mélangés.

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();

}

Usage:

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);
}
4

Je viens de trouver un autre moyen de le faire. Pas encore une opération, mais la jeter pour voir ce que les autres en pensent.

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

Qu'en est-il de

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 ... Je crois que vous devez faire autant d'appels que les types de fichiers souhaités. 

Je créerais moi-même une fonction prenant un tableau sur des chaînes avec les extensions dont j'ai besoin, puis itérerais sur ce tableau en passant tous les appels nécessaires. Cette fonction renverrait une liste générique des fichiers correspondant aux extensions que j'avais envoyées.

J'espère que ça aide.

2
sebagomez

Faites les extensions que vous voulez une chaîne i.e ".mp3.jpg.wma.wmf" puis vérifiez si chaque fichier contient l'extension que vous voulez . Cela fonctionne avec .net 2.0 car il n'utilise pas LINQ.

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

   }
}

L’avantage de cette approche est que vous pouvez ajouter ou supprimer des extensions sans modifier le code, c’est-à-dire pour ajouter des images png, écrivez simplement myExtensions = ". Jpg.mp3.png".

2
Evado

dans .NET 2.0 (pas de 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()
}

Alors utilisez-le:

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

Je me demande pourquoi il y a tant de "solutions" affichées?

Si ma bonne nouvelle sur le fonctionnement de GetFiles est correcte, il n’ya que deux options et chacune des solutions ci-dessus peut être réduite à celles-ci:

  1. GetFiles, puis filter: Rapide, mais tue la mémoire en raison de la surcharge de stockage jusqu’à ce que les filtres soient appliqués

  2. Filtrer lorsque GetFiles: Plus le nombre de filtres définis est élevé, mais plus la mémoire utilisée est faible, car aucun temps système n'est stocké.
    Ceci est expliqué dans l'un des messages ci-dessus avec un repère impressionnant: chaque option de filtre provoque une opération GetFile distincte de sorte que la même partie du disque dur soit lue plusieurs fois.

À mon avis, l’option 1) est préférable, mais l’utilisation de SearchOption.AllDirectories sur des dossiers tels que C:\utiliserait d’énormes quantités de mémoire.
Je ferais donc simplement une sous-méthode récursive qui parcourt tous les sous-dossiers en utilisant l’option 1).

Cela ne devrait provoquer qu'une seule opération GetFiles sur chaque dossier et donc être rapide (Option 1), mais n'utilisez qu'une petite quantité de mémoire car les filtres sont appliqués après la lecture de chaque sous-dossier -> la surcharge est supprimée après chaque sous-dossier.

S'il vous plait corrigez moi si je me trompe. Je suis comme je l'ai dit assez nouveau en programmation, mais je veux acquérir une compréhension plus profonde des choses pour finalement devenir bon dans ce domaine :)

1
Janis

J'avais le même problème et je ne trouvais pas la bonne solution. J'ai donc écrit une fonction appelée 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();
}

Cette fonction appellera Directory.Getfiles() une seule fois.

Par exemple, appelez la fonction comme ceci:

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

EDIT: Pour obtenir un fichier avec plusieurs extensions, utilisez celui-ci:

/// <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 "";
    }

Par exemple, appelez la fonction comme ceci:

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

Si vous utilisez VB.NET (ou importez la dépendance dans votre projet C #), il existe en réalité une méthode pratique qui permet de filtrer plusieurs extensions:

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

En VB.NET, vous pouvez y accéder via l’espace My-namespace:

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

Malheureusement, ces méthodes pratiques ne prennent pas en charge une variante évaluée paresseuse, comme le fait Directory.EnumerateFiles().

0
Crusha K. Rool

je ne sais pas quelle solution est la meilleure, mais j’utilise ceci:

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

Utiliser le modèle de recherche GetFiles pour filtrer l'extension n'est pas sûr !! Par exemple, vous avez deux fichiers Test1.xls et Test2.xlsx et vous souhaitez filtrer le fichier xls à l'aide du modèle de recherche * .xls, mais GetFiles renvoie les deux Test1. xls et Test2.xlsx Je n'étais pas au courant de cela et j'ai eu une erreur dans l'environnement de production lorsque certains fichiers temporaires ont été soudainement traités comme de bons fichiers. Le modèle de recherche était * .txt et les fichiers temporaires étaient nommés * .txt20181028_100753898 Ainsi, le modèle de recherche ne peut pas être approuvé, vous devez également vérifier les noms de fichiers.

0
WillyS