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.

Seb Nilsson
la source
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));
}
Daniel B
la source
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

Jgauffin
la source
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

Ulrik Magnusson
la source
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();
Marc
la source
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();
Jodrell
la source
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();
drzaus
la source
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"))
Jonathan
la source
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

Mario Vernari
la source
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();
Olivier Jacot-Descombes
la source
2

J'essaierais de spécifier quelque chose comme

var searchPattern = "as?x";

ça devrait marcher.

Davide Piras
la source
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();
    }
A.Ramazani
la source
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);
    }
Yossi Goldberg
la source
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 )

BigChief
la source
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()));
}
Gildor
la source
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.

Artorias2718
la source
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

Rijul Sudhir
la source
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.

Carlos David López
la source
1

Tu peux le faire comme ça

new DirectoryInfo(path).GetFiles().Where(Current => Regex.IsMatch(Current.Extension, "\\.(aspx|ascx)", RegexOptions.IgnoreCase)
Gigaoctet
la source
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();
romain
la source
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
qfactor77
la source
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