SearchPattern per estensioni di file multiple per System.IO.Directory.GetFiles


140

Qual è la sintassi per l'impostazione di più estensioni di file come searchPatternattivata Directory.GetFiles()? Ad esempio, filtrando i file con estensioni .aspx e .ascx .

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

Aggiornamento : LINQ non è un'opzione , deve essere searchPatternpassata GetFiles, come specificato nella domanda.


Non penso ce ne sia. Elenca tutti i file, quindi filtra manualmente o esegui un'unione su più ricerche. Ma sono abbastanza sicuro di aver già visto questa domanda esatta su SO.
CodesInCos


Precedentemente chiesto e risposto qui: stackoverflow.com/questions/163162/…
David

Risposte:


41

Credo che non esista una soluzione "pronta all'uso", questa è una limitazione del metodo Directory.GetFiles.

È abbastanza facile scrivere il proprio metodo, ecco un esempio .

Il codice potrebbe essere:

/// <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
Questo è un modo molto insufficiente di farlo, poiché eseguirai il ciclo dell'intera directory per ciascun filtro. Invece dovresti controllare per ogni file se ha il filtro quindi aggiungere per fare l'elenco. È possibile utilizzare la risposta spiegata in questa discussione: stackoverflow.com/questions/3754118/...
ot0

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

Modifica 23/07/2014

È possibile farlo in .NET 4.5 per un'enumerazione più veloce:

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

Directory.EnumerateFiles in MSDN


5
@Mario Vernari: GetFilesritorna string[].
Jgauffin,

4
È necessario rimuovere * dall'argomento EndsWith (), non esegue corrispondenze con caratteri jolly.
Hans Passant,

3
se confronta le estensioni del file, restituirà la corrispondenza esatta come '.Where (file => new FileInfo (file) .Extension.Equals (". aspx") || new FileInfo (file) .Extension.Equals (". ascx") ) "
Damith,

3
Da non dimenticare il nuovo .NET4 Directory.EnumerateFilesper una performance spinta ... stackoverflow.com/questions/5669617/...
drzaus

6
E puoi sempre usare file.EndsWith("...", StringComparison.InvariantCultureIgnoreCase);piuttosto cheToLower
drzaus il

30

GetFiles può abbinare solo un singolo pattern, ma puoi usare Linq per invocare GetFiles con più pattern:

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

Vedi la sezione commenti qui: http://www.codeproject.com/KB/aspnet/NET_DirectoryInfo.aspx


2
Si scontreranno se gli schemi si sovrappongono. Ad es new string[]{"*.txt","filename.*"}. Tuttavia, la chiamata a Distinctnon risolve effettivamente questo problema, poiché gli oggetti FileInfo si confrontano usando l'uguaglianza di riferimento, non l'uguaglianza semantica. Potrebbe essere risolto rimuovendo Distincto passando un IEqualityComparer<FileInfo>. A cura di fare il primo.
Brian

Penserei che SelectManyripeterà (e ancora) la stessa struttura di file, quindi potrebbe non essere ottimale in termini di prestazioni.
Dejan

28

Mi piace questo metodo, perché è leggibile ed evita più iterazioni della directory:

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

2
Mi piace molto di più perché non devo analizzare il mio array di estensioni e aggiungerlo a regex o ad altri lavori manuali. Grazie!
Ian Newland,

@Jodrell, o semplicemente aHashSet<string>
Jodrell,

HashSet <stringa> anziché un array per l'estensione non ha senso in questo caso, poiché il numero di estensioni è limitato e l'array viene ripetuto per ogni file, fino a quando EndsWith () diventa true. Se il metodo deve essere ottimizzato per le prestazioni per un numero molto elevato di estensioni, è possibile utilizzare un Hashset. Per avere effetto, l'estensione di ciascun file dovrebbe quindi essere abbinata in modo esplicito (dividere, quindi abbinare) invece del metodo EndsWith (). Ciò danneggerà la leggibilità e non sarà di alcuna utilità nella maggior parte dei casi di utilizzo nella vita reale. Ho quindi ripristinato la modifica della community.
Marc,

15

Temo che dovrai fare qualcosa del genere, da qui ho mutato la regex .

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

questo sembra essere un buon approccio, la parte mancante è avere un'espressione regolare (funzionante) testata
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();

Oppure, potrebbe essere più veloce dividere e unire i tuoi globs (almeno sembra più pulito):

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

e reinserire sul domanda "originale" con più dettagli - stackoverflow.com/questions/163162/...
drzaus

6

La soluzione facile da ricordare, pigra e forse imperfetta:

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

4

Vorrei usare quanto segue:

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: corretta mancata corrispondenza tra Directory e DirectoryInfo


3

Un modo più efficiente di ottenere file con le estensioni ".aspx" e ".ascx" che evita di interrogare più volte il file system ed evita di restituire molti file indesiderati, è pre-filtrare i file utilizzando un modello di ricerca approssimativo e per affinare il risultato in seguito:

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

2

Vorrei provare a specificare qualcosa di simile

var searchPattern = "as?x";

dovrebbe funzionare.


Hah! Temevo che aspx e ascx fossero troppo simili e avrebbero reso una soluzione di hacking come questa. Voglio qualcosa di generale.
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

Invece della funzione EndsWith, sceglierei di utilizzare il Path.GetExtension()metodo. Ecco l'esempio completo:

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

o:

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

(Usa StringComparison.OrdinalIgnoreCasese ti preoccupi delle prestazioni: confronti di stringhe MSDN )


1

assomiglia a questa demo:

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
Hai quello Path.GetExtensionche puoi usare.
Jgauffin,

1

@ Daniele B, grazie per il suggerimento di scrivere la mia versione di questa funzione. Ha lo stesso comportamento di Directory.GetFiles, ma supporta il filtro 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();
    }

L'ho trovato utile, quindi ho pensato di condividere.


1

versione c # della risposta di @ qfactor77. Questo è il modo migliore senza 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);

ora restituisce filePatharray di stringhe. All'inizio hai bisogno

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

inoltre è necessario aggiungere riferimento a Microsoft.VisualBasic


1

Ho fatto un modo semplice per cercare tutte le estensioni di cui hai bisogno e senza 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();

Lavorando su .Net Standard 2.0.


1

Puoi farlo in questo modo

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

La domanda è: LINQ non è un'opzione, quindi questa risposta non è utile
Arci

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

Aggiungi ulteriori spiegazioni per il codice. Potrebbe aiutare OP a capire meglio la tua risposta.
user2339071

-2

Vorrei solo dire che se si utilizza FileIO.FileSystem.GetFilesinvece di Directory.GetFiles, consentirà una serie di caratteri jolly.

Per esempio:

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

Dove si acquisisce FileIO?
Joel Martinez,

1
Dovrebbe essere già incluso nel tuo ambiente in Visual Studio (2015). Fa parte dello spazio dei nomi Microsoft.VisualBasic. Nel mio caso è VisualBasic perché è la mia lingua preferita.
qfactor77,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.