c# - Multiple file-extensions searchPattern para System.IO.Directory.GetFiles




.net (12)

¿Cuál es la sintaxis para configurar múltiples extensiones de archivo como searchPattern en Directory.GetFiles() ? Por ejemplo, filtrando archivos con extensiones .aspx y .ascx .

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

Actualización : LINQ no es una opción , tiene que ser un searchPattern pasado a GetFiles , como se especifica en la pregunta.


@ Daniel B, gracias por la sugerencia de escribir mi propia versión de esta función. Tiene el mismo comportamiento que Directory.GetFiles, pero admite el filtrado de expresiones regulares.

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

Lo encontré útil, así que pensé que lo compartiría.


Creo que no hay una solución "lista para usar", eso es una limitación del método Directory.GetFiles.

Sin embargo, es bastante fácil escribir su propio método, aquí hay un example .

El código podría ser:

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

GetFiles solo puede coincidir con un patrón único, pero puede usar Linq para invocar GetFiles con múltiples patrones:

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

Vea la sección de comentarios aquí: http://www.codeproject.com/KB/aspnet/NET_DirectoryInfo.aspx


Intentaré especificar algo como

var searchPattern = "as?x";

deberia de funcionar.


Me gusta este método, porque es legible y evita múltiples iteraciones del directorio:

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

Me temo que tendrás que hacer algo como esto, he mutado la expresión regular desde here .

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

Una forma más eficiente de obtener archivos con las extensiones ".aspx" y ".ascx" que evita consultar el sistema de archivos varias veces y evita devolver muchos archivos no deseados, es prefiltrar los archivos utilizando un patrón de búsqueda aproximado y para refinar el resultado después:

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

Versión c # de la respuesta de @ qfactor77. Esta es la mejor manera sin 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);

ahora devuelve la matriz de cadena de filePath . Al principio necesitas

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

también necesita agregar referencia a Microsoft.VisualBasic


mira como esta demostración:

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

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

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

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

O bien, puede ser más rápido dividir y unir tus globs (al menos se ve más limpio):

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




system.io.directory