Recherche d'extensions de fichiers multiples pour System.IO.Directory.GetFiles


140

Quelle est la syntaxe pour définir plusieurs extensions de fichiersearchPattern sur Directory.GetFiles()ON? Par exemple, filtrer les fichiers avec les extensions .aspx et .ascx .

// TODO: Set the string 'searchPattern' to only get files with
// the extension '.aspx' and '.ascx'.
var filteredFiles = Directory.GetFiles(path, searchPattern);

Mise à jour : LINQ n'est pas une option , il doit être searchPatterntransmis GetFiles, comme spécifié dans la question.


Je ne pense pas qu'il y en ait. Répertoriez tous les fichiers, puis filtrez manuellement ou effectuez une union sur plusieurs chercheurs. Mais je suis à peu près sûr d'avoir déjà vu cette question exacte sur SO.
CodesInChaos


Auparavant demandé et répondu ici: stackoverflow.com/questions/163162/…
David

Réponses:


41

Je crois qu'il n'y a pas de solution «prête à l'emploi», c'est une limitation de la méthode Directory.GetFiles.

Cependant, il est assez facile d'écrire votre propre méthode, voici un exemple .

Le code pourrait être:

/// <summary>
/// Returns file names from given folder that comply to given filters
/// </summary>
/// <param name="SourceFolder">Folder with files to retrieve</param>
/// <param name="Filter">Multiple file filters separated by | character</param>
/// <param name="searchOption">File.IO.SearchOption, 
/// could be AllDirectories or TopDirectoryOnly</param>
/// <returns>Array of FileInfo objects that presents collection of file names that 
/// meet given filter</returns>
public string[] getFiles(string SourceFolder, string Filter, 
 System.IO.SearchOption searchOption)
{
 // ArrayList will hold all file names
ArrayList alFiles = new ArrayList();

 // Create an array of filter string
 string[] MultipleFilters = Filter.Split('|');

 // for each filter find mathing file names
 foreach (string FileFilter in MultipleFilters)
 {
  // add found file names to array list
  alFiles.AddRange(Directory.GetFiles(SourceFolder, FileFilter, searchOption));
 }

 // returns string array of relevant file names
 return (string[])alFiles.ToArray(typeof(string));
}

7
C'est une manière très insuffisante de le faire, puisque vous bouclerez le répertoire entier pour chaque filtre. Au lieu de cela, vous devriez vérifier pour chaque fichier s'il a le filtre, puis ajouter pour faire la liste. Vous pouvez utiliser la réponse expliquée dans ce fil: stackoverflow.com/questions/3754118
...

191
var filteredFiles = Directory
    .GetFiles(path, "*.*")
    .Where(file => file.ToLower().EndsWith("aspx") || file.ToLower().EndsWith("ascx"))
    .ToList();

Modifier 23/07/2014

Vous pouvez le faire dans .NET 4.5 pour une énumération plus rapide:

var filteredFiles = Directory
    .EnumerateFiles(path) //<--- .NET 4.5
    .Where(file => file.ToLower().EndsWith("aspx") || file.ToLower().EndsWith("ascx"))
    .ToList();

Directory.EnumerateFiles dans MSDN


5
@Mario Vernari: GetFilesrevient string[].
jgauffin

4
Vous devez supprimer le * de l'argument EndsWith (), il ne fait pas de correspondances génériques.
Hans Passant

3
si comparer les extensions du fichier, il retournera une correspondance exacte comme '.Where (fichier => nouveau FileInfo (fichier) .Extension.Equals (". aspx") || nouveau FileInfo (fichier) .Extension.Equals (". ascx") ) '
Damith

3
N'oubliez pas le nouveau .NET4 Directory.EnumerateFilespour une amélioration des performances ... stackoverflow.com/questions/5669617/…
drzaus

6
Et vous pouvez toujours utiliser file.EndsWith("...", StringComparison.InvariantCultureIgnoreCase);plutôt queToLower
drzaus

30

GetFiles ne peut correspondre qu'à un seul modèle, mais vous pouvez utiliser Linq pour appeler GetFiles avec plusieurs modèles:

FileInfo[] fi = new string[]{"*.txt","*.doc"}
    .SelectMany(i => di.GetFiles(i, SearchOption.AllDirectories))
    .ToArray();

Voir la section commentaires ici: http://www.codeproject.com/KB/aspnet/NET_DirectoryInfo.aspx


2
Ils entreront en collision si les motifs se chevauchent. Par exemple, new string[]{"*.txt","filename.*"}. Cependant, l'appel à Distinctne résout pas réellement ce problème, car les objets FileInfo se comparent en utilisant l'égalité de référence et non l'égalité sémantique. Il peut être corrigé en supprimant le Distinctou en lui passant un fichier IEqualityComparer<FileInfo>. Édité pour faire l'ancien.
Brian

Je pense que SelectManycela itérera encore (et encore) sur la même structure de fichiers, ce qui pourrait être sous-optimal en termes de performances.
Dejan

28

J'aime cette méthode, car elle est lisible et évite les itérations multiples du répertoire:

var allowedExtensions = new [] {".doc", ".docx", ".pdf", ".ppt", ".pptx", ".xls", ".xslx"}; 
var files = Directory
    .GetFiles(folder)
    .Where(file => allowedExtensions.Any(file.ToLower().EndsWith))
    .ToList();

2
J'aime beaucoup mieux parce que je n'ai pas besoin d'analyser mon tableau d'extension et de l'ajouter à regex ou à tout autre travail manuel. Merci!
Ian Newland

@Jodrell, ou simplement unHashSet<string>
Jodrell

HashSet <string> au lieu d'un tableau pour l'extension n'a aucun sens ici, car le nombre d'extensions est limité et le tableau est itéré pour chaque fichier, jusqu'à ce que EndsWith () devienne vrai. Si la méthode doit être optimisée pour les performances d'un très grand nombre d'extensions, un Hashset peut être utilisé. Pour prendre effet, l'extension de chaque fichier devrait alors être mise en correspondance explicitement (fractionner, puis correspondre) au lieu de la méthode EndsWith (). Cela nuira à la lisibilité et ne sera d'aucune utilité significative dans la plupart sinon tous les cas d'utilisation réels. J'ai donc annulé la modification de la communauté.
Marc

15

J'ai peur que vous deviez faire quelque chose comme ça, j'ai muté le regex d' ici .

var searchPattern = new Regex(
    @"$(?<=\.(aspx|ascx))", 
    RegexOptions.IgnoreCase);
var files = Directory.EnumerateFiles(path)
    .Where(f => searchPattern.IsMatch(f))
    .ToList();

cela semble être une bonne approche, la partie manquante est d'avoir une expression régulière testée (fonctionnelle)
Junior Mayhé

14
var filteredFiles = Directory
    .EnumerateFiles(path, "*.*") // .NET4 better than `GetFiles`
    .Where(
        // ignorecase faster than tolower...
        file => file.ToLower().EndsWith("aspx")
        || file.EndsWith("ascx", StringComparison.OrdinalIgnoreCase))
    .ToList();

Ou, il peut être plus rapide de diviser et de fusionner vos globes (au moins, cela semble plus propre):

"*.ext1;*.ext2".Split(';')
    .SelectMany(g => Directory.EnumerateFiles(path, g))
    .ToList();

et republication sur la question "originale" avec plus de détails - stackoverflow.com/questions/163162
...

6

La solution facile à retenir, paresseuse et peut-être imparfaite:

Directory.GetFiles(dir, "*.dll").Union(Directory.GetFiles(dir, "*.exe"))

4

J'utiliserais ce qui suit:

var ext = new string[] { ".ASPX", ".ASCX" };
FileInfo[] collection = (from fi in new DirectoryInfo(path).GetFiles()
                         where ext.Contains(fi.Extension.ToUpper())
                         select fi)
                         .ToArray();

EDIT: correction du décalage dû entre Directory et DirectoryInfo


3

Un moyen plus efficace d'obtenir des fichiers avec les extensions ".aspx" et ".ascx" qui évite d'interroger le système de fichiers plusieurs fois et évite de renvoyer un grand nombre de fichiers indésirables, consiste à pré-filtrer les fichiers en utilisant un modèle de recherche approximatif et pour affiner le résultat par la suite:

var filteredFiles = Directory.GetFiles(path, "*.as?x")
    .Select(f => f.ToLowerInvariant())
    .Where(f => f.EndsWith("px") || f.EndsWith("cx"))
    .ToList();

2

J'essaierais de spécifier quelque chose comme

var searchPattern = "as?x";

ça devrait marcher.


Hah! J'avais peur que aspx et ascx soient trop similaires et ne rendraient une solution de hack comme celle-ci. Je veux quelque chose de général.
Seb Nilsson

2
    /// <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
    public static bool CheckFiles(string pathA, string pathB)
    {
        string[] extantionFormat = new string[] { ".war", ".pkg" };
        return CheckFiles(pathA, pathB, extantionFormat);
    }
    public static bool CheckFiles(string pathA, string pathB, string[] extantionFormat)
    {
        System.IO.DirectoryInfo dir1 = new System.IO.DirectoryInfo(pathA);
        System.IO.DirectoryInfo dir2 = new System.IO.DirectoryInfo(pathB);
        // Take a snapshot of the file system. list1/2 will contain only WAR or PKG 
        // files
        // fileInfosA will contain all of files under path directories 
        FileInfo[] fileInfosA = dir1.GetFiles("*.*", 
                              System.IO.SearchOption.AllDirectories);
        // list will contain all of files that have ..extantion[]  
        // Run on all extantion in extantion array and compare them by lower case to 
        // the file item extantion ...
        List<System.IO.FileInfo> list1 = (from extItem in extantionFormat
                                          from fileItem in fileInfosA
                                          where extItem.ToLower().Equals 
                                          (fileItem.Extension.ToLower())
                                          select fileItem).ToList();
        // Take a snapshot of the file system. list1/2 will contain only WAR or  
        // PKG files
        // fileInfosA will contain all of files under path directories 
        FileInfo[] fileInfosB = dir2.GetFiles("*.*", 
                                       System.IO.SearchOption.AllDirectories);
        // list will contain all of files that have ..extantion[]  
        // Run on all extantion in extantion array and compare them by lower case to 
        // the file item extantion ...
        List<System.IO.FileInfo> list2 = (from extItem in extantionFormat
                                          from fileItem in fileInfosB
                                          where extItem.ToLower().Equals            
                                          (fileItem.Extension.ToLower())
                                          select fileItem).ToList();
        FileCompare myFileCompare = new FileCompare();
        // This query determines whether the two folders contain 
        // identical file lists, based on the custom file comparer 
        // that is defined in the FileCompare class. 
        return list1.SequenceEqual(list2, myFileCompare);
    }

2

Au lieu de la fonction EndsWith, je choisirais d'utiliser la Path.GetExtension()méthode à la place. Voici l'exemple complet:

var filteredFiles = Directory.EnumerateFiles( path )
.Where(
    file => Path.GetExtension(file).Equals( ".aspx", StringComparison.OrdinalIgnoreCase ) ||
            Path.GetExtension(file).Equals( ".ascx", StringComparison.OrdinalIgnoreCase ) );

ou:

var filteredFiles = Directory.EnumerateFiles(path)
.Where(
    file => string.Equals( Path.GetExtension(file), ".aspx", StringComparison.OrdinalIgnoreCase ) ||
            string.Equals( Path.GetExtension(file), ".ascx", StringComparison.OrdinalIgnoreCase ) );

(À utiliser StringComparison.OrdinalIgnoreCasesi vous vous souciez des performances: comparaisons de chaînes MSDN )


1

ressemble à cette démo:

void Main()
{
    foreach(var f in GetFilesToProcess("c:\\", new[] {".xml", ".txt"}))
        Debug.WriteLine(f);
}
private static IEnumerable<string> GetFilesToProcess(string path, IEnumerable<string> extensions)
{
   return Directory.GetFiles(path, "*.*")
       .Where(f => extensions.Contains(Path.GetExtension(f).ToLower()));
}

1
Vous avez Path.GetExtensionque vous pouvez utiliser.
jgauffin

1

@Daniel B, merci pour la suggestion d'écrire ma propre version de cette fonction. Il a le même comportement que Directory.GetFiles, mais prend en charge le filtrage regex.

string[] FindFiles(FolderBrowserDialog dialog, string pattern)
    {
        Regex regex = new Regex(pattern);

        List<string> files = new List<string>();
        var files=Directory.GetFiles(dialog.SelectedPath);
        for(int i = 0; i < files.Count(); i++)
        {
            bool found = regex.IsMatch(files[i]);
            if(found)
            {
                files.Add(files[i]);
            }
        }

        return files.ToArray();
    }

Je l'ai trouvé utile, alors j'ai pensé partager.


1

version c # de la réponse de @ qfactor77. C'est le meilleur moyen sans LINQ.

string[] wildcards= {"*.mp4", "*.jpg"};
ReadOnlyCollection<string> filePathCollection = FileSystem.GetFiles(dirPath, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, wildcards);
string[] filePath=new string[filePathCollection.Count];
filePathCollection.CopyTo(filePath,0);

retourne maintenant filePathun tableau de chaînes. Au début tu as besoin

using Microsoft.VisualBasic.FileIO;
using System.Collections.ObjectModel;

vous devez également ajouter une référence à Microsoft.VisualBasic


1

J'ai fait un moyen simple de rechercher autant d'extensions que vous en avez besoin, et sans ToLower (), RegEx, foreach ...

List<String> myExtensions = new List<String>() { ".aspx", ".ascx", ".cs" }; // You can add as many extensions as you want.
DirectoryInfo myFolder = new DirectoryInfo(@"C:\FolderFoo");
SearchOption option = SearchOption.TopDirectoryOnly; // Use SearchOption.AllDirectories for seach in all subfolders.
List<FileInfo> myFiles = myFolder.EnumerateFiles("*.*", option)
    .Where(file => myExtensions
    .Any(e => String.Compare(file.Extension, e, CultureInfo.CurrentCulture, CompareOptions.IgnoreCase) == 0))
    .ToList();

Travailler sur .Net Standard 2.0.


1

Tu peux le faire comme ça

new DirectoryInfo(path).GetFiles().Where(Current => Regex.IsMatch(Current.Extension, "\\.(aspx|ascx)", RegexOptions.IgnoreCase)

Dans la question est: LINQ n'est pas une option, donc cette réponse n'est pas utile
Arci

0
var filtered = Directory.GetFiles(path)
    .Where(file => file.EndsWith("aspx", StringComparison.InvariantCultureIgnoreCase) || file.EndsWith("ascx", StringComparison.InvariantCultureIgnoreCase))
    .ToList();

Ajoutez une explication supplémentaire pour le code. Cela pourrait aider OP à mieux comprendre votre réponse.
user2339071

-2

Je voudrais juste dire que si vous utilisez à la FileIO.FileSystem.GetFilesplace deDirectory.GetFiles , cela autorisera un tableau de caractères génériques.

Par exemple:

Dim wildcards As String() = {"*.html", "*.zip"}
Dim ListFiles As List(Of String) = FileIO.FileSystem.GetFiles(directoryyouneed, FileIO.SearchOption.SearchTopLevelOnly, wildcards).ToList

Où acquiert-on FileIO?
Joel Martinez le

1
Il doit déjà être inclus dans votre environnement dans Visual Studio (2015). Il fait partie de l'espace de noms Microsoft.VisualBasic. Dans mon cas, c'est VisualBasic parce que c'est ma langue de choix.
qfactor77
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.