¿Puedes llamar a Directory.GetFiles () con múltiples filtros?

Estoy intentando usar el método Directory.GetFiles() para recuperar una lista de archivos de varios tipos, como mp3 y jpg . He intentado los dos siguientes sin suerte:

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

¿Hay alguna manera de hacer esto en una llamada?

Para .NET 4.0 y posterior,

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

Para versiones anteriores de .NET,

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

editar: Por favor, lea los comentarios. La mejora que sugiere Paul Farry y el problema de memoria / rendimiento que señala Christian.K son muy importantes.

Qué tal esto:

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

Lo encontré aquí (en los comentarios): http://sofes.miximages.com/c%23/ppre codestring 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 }

para

 var exts = new[] { "mp3", "jpg" }; 

Tú podrías:

 public IEnumerable FilterFiles(string path, params string[] exts) { return Directory .EnumerateFiles(path, "*.*") .Where(file => exts.Any(x => file.EndsWith(x, StringComparison.OrdinalIgnoreCase))); } 
  • No olvide el nuevo .NET4 Directory.EnumerateFiles para un aumento del rendimiento ( ¿Cuál es la diferencia entre Directory.EnumerateFiles vs Directory.GetFiles? )
  • “IgnoreCase” debería ser más rápido que “ToLower” ( .EndsWith("aspx", StringComparison.OrdinalIgnoreCase) lugar de .ToLower().EndsWith("aspx") )

Pero el beneficio real de EnumerateFiles aparece cuando se dividen los filtros y se combinan los resultados:

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

Se vuelve un poco más rápido si no tiene que convertirlos en globs (es decir, exts = new[] {"*.mp3", "*.jpg"} ya).

Evaluación de rendimiento basada en la siguiente prueba de LinqPad (nota: Perf simplemente repite al delegado 10000 veces) https://gist.github.com/zaus/7454021

(reenviado y extendido desde ‘duplicado’ ya que esa pregunta no solicitó específicamente ningún LINQ: Multiple file-extensions searchPattern para System.IO.Directory.GetFiles )

Sé que es una pregunta antigua, pero LINQ: (.NET40 +)

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

Otra forma de usar Linq, pero sin tener que devolver todo y filtrar eso en la memoria.

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

En realidad, se trata de 2 llamadas a GetFiles() , pero creo que es coherente con el espíritu de la pregunta y las devuelve en un enumerable.

También hay una solución de descenso que parece no tener ningún gasto de memoria o rendimiento y ser bastante elegante:

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

Nop. Pruebe lo siguiente:

 List _searchPatternList = new List(); ... List fileList = new List(); 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 ) { ...; } 

Tomado de: http://sofes.miximages.com/c%23/ppre codevar set = new HashSetstring { .mp3, .jpg” };

Entonces

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

o

 from file in Directory.GetFiles(path, "*.*", SearchOption.AllDirectories) from ext in set where String.Equals(ext, new FileInfo(file).Extension, StringComparison.OrdinalIgnoreCase) select file; 

No puedo usar el método .Where porque estoy progtwigndo en .NET Framework 2.0 (Linq solo es compatible con .NET Framework 3.5+).

El código a continuación no .CaB mayúsculas y minúsculas (por lo que también se .CaB o .cab ).

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

La siguiente función busca en múltiples patrones, separados por comas. También puede especificar una exclusión, por ejemplo: “! Web.config” buscará todos los archivos y excluirá “web.config”. Los patrones pueden ser mixtos.

 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 workers = new List(); List files = new List(); 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(); } 

Uso:

 foreach (string file in FindFiles(@"D:\628.2.11", @"!*.config, !*.js", SearchOption.AllDirectories)) { Console.WriteLine(file); } 
 List FileList = new List(); DirectoryInfo di = new DirectoryInfo("C:\\DirName"); IEnumerable fileList = di.GetFiles("*.*"); //Create the query IEnumerable 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); } 

Acabo de encontrar otra forma de hacerlo. Todavía no es una operación, sino que la arroja para ver qué piensan los demás sobre ella.

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

Qué pasa

 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 filesAll = new List(totalArraySizeAll); filesAll.AddRange(filesPNG); filesAll.AddRange(filesJPG); filesAll.AddRange(filesJPEG); 

Haga las extensiones que desea una cadena, es decir, “.mp3.jpg.wma.wmf” y luego verifique si cada archivo contiene la extensión que desea. Esto funciona con .net 2.0 ya que no usa 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 } } 

La ventaja de este enfoque es que puede agregar o eliminar extensiones sin editar el código, es decir, para agregar imágenes png, simplemente escriba myExtensions = “. Jpg.mp3.png”.

 ///  /// Returns the names of files in a specified directories that match the specified patterns using LINQ ///  /// The directories to seach /// the list of search patterns ///  /// The list of files that match the specified pattern 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(); } 

Nop … Creo que tienes que hacer tantas llamadas como los tipos de archivos que quieras.

Crearía una función yo mismo tomando una matriz en cadenas con las extensiones que necesito y luego iteraría en esa matriz haciendo todas las llamadas necesarias. Esa función devolvería una lista genérica de los archivos que coinciden con las extensiones que envié.

Espero eso ayude.

en .NET 2.0 (sin Linq):

 public static List GetFilez(string path, System.IO.SearchOption opt, params string[] patterns) { List filez = new List(); foreach (string pattern in patterns) { filez.AddRange( System.IO.Directory.GetFiles(path, pattern, opt) ); } // filez.Sort(); // Optional return filez; // Optional: .ToArray() } 

Entonces úsalo:

 foreach (string fn in GetFilez(path , System.IO.SearchOption.AllDirectories , "*.xml", "*.xml.rels", "*.rels")) {} 
 DirectoryInfo directory = new DirectoryInfo(Server.MapPath("~/Contents/")); //Using Union FileInfo[] files = directory.GetFiles("*.xlsx") .Union(directory .GetFiles("*.csv")) .ToArray(); 

Tuve el mismo problema y no pude encontrar la solución adecuada, así que escribí una función llamada GetFiles:

 ///  /// Get all files with a specific extension ///  /// string list of all the extensions /// string of the location /// array of all the files with the specific extensions public string[] GetFiles(List extensionsToCompare, string Location) { List files = new List(); foreach (string file in Directory.GetFiles(Location)) { if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.')+1).ToLower())) files.Add(file); } files.Sort(); return files.ToArray(); } 

Esta función llamará a Directory.Getfiles() solo una vez.

Por ejemplo, llame a la función de esta manera:

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

EDITAR: Para obtener un archivo con múltiples extensiones, use este:

 ///  /// Get the file with a specific name and extension ///  /// the name of the file to find /// string list of all the extensions /// string of the location /// file with the requested filename public string GetFile( string filename, List 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 ""; } 

Por ejemplo, llame a la función de esta manera:

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

Me pregunto por qué hay tantas “soluciones” publicadas.

Si mi comprensión de novato sobre cómo funciona GetFiles es correcta, solo hay dos opciones y cualquiera de las soluciones anteriores se puede reducir a estas:

  1. GetFiles, luego filtro: rápido, pero un destructor de memoria debido al almacenamiento de sobrecarga hasta que se apliquen los filtros

  2. Filtre mientras GetFiles: Más lento cuanto más filtros se establecen, pero menos uso de memoria, ya que no se almacena ningún gasto adicional.
    Esto se explica en una de las publicaciones anteriores con un punto de referencia impresionante: cada opción de filtro causa una operación separada de GetFile por lo que la misma parte del disco duro se lee varias veces.

En mi opinión, la Opción 1) es mejor, pero usar SearchOption.AllDirectories en carpetas como C: \ usaría grandes cantidades de memoria.
Por lo tanto, solo haría un submétodo recursivo que pase por todas las subcarpetas usando la opción 1)

Esto debería causar solo 1 operación GetFiles en cada carpeta y por lo tanto ser rápido (Opción 1), pero use solo una pequeña cantidad de memoria ya que los filtros se aplican después de la lectura de cada subcarpeta -> la sobrecarga se elimina después de cada subcarpeta.

Por favor, corríjame si estoy equivocado. Soy como dije bastante nuevo en la progtwigción, pero quiero obtener una comprensión más profunda de las cosas para finalmente ser bueno en esto 🙂

No sé qué solución es mejor, pero uso esto:

 String[] ext = "*.ext1|*.ext2".Split('|'); List files = new List(); foreach (String tmp in ext) { files.AddRange(Directory.GetFiles(dir, tmp, SearchOption.AllDirectories)); } 

Si está usando VB.NET (o importó la dependencia en su proyecto de C #), existe realmente un método de conveniencia que permite filtrar varias extensiones:

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

En VB.NET esto se puede acceder a través del espacio de nombres Mi:

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

Lamentablemente, estos métodos de conveniencia no admiten una variante evaluada de forma diferida como Directory.EnumerateFiles() .

O simplemente puede convertir la cadena de extensiones a String ^

 vector  extensions = { "*.mp4", "*.avi", "*.flv" }; for (int i = 0; i < extensions.size(); ++i) { String^ ext = gcnew String(extensions[i].c_str());; String^ path = "C:\\Users\\Eric\\Videos"; array^files = Directory::GetFiles(path,ext); Console::WriteLine(ext); cout << " " << (files->Length) << endl; } 

Espero que esto ayude a alguien:

 //getting only playable Audio/Video Files from open dialog OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = ""All Media Files|*.wav;*.aac;*.wma;*.wmv;*.avi;*.mpg;*.mpeg;*.m1v;*.mp2;*.mp3;*.mpa;*.mpe;*.m3u;*.mp4;*.mov;*.3g2;*.3gp2;*.3gp;*.3gpp;*.m4a;*.cda;*.aif;*.aifc;*.aiff;*.mid;*.midi;*.rmi;*.mkv;*.WAV;*.AAC;*.WMA;*.WMV;*.AVI;*.MPG;*.MPEG;*.M1V;*.MP2;*.MP3;*.MPA;*.MPE;*.M3U;*.MP4;*.MOV;*.3G2;*.3GP2;*.3GP;*.3GPP;*.M4A;*.CDA;*.AIF;*.AIFC;*.AIFF;*.MID;*.MIDI;*.RMI;*.MKV"; dlg.ShowDialog();