Puoi chiamare Directory.GetFiles () con più filtri?

Sto cercando di utilizzare il metodo Directory.GetFiles() per recuperare un elenco di file di più tipi, come mp3 e jpg . Ho provato entrambi i seguenti senza fortuna:

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

C’è un modo per farlo in una sola chiamata?

Per .NET 4.0 e versioni successive,

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

Per le versioni precedenti di .NET,

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

modifica: si prega di leggere i commenti. Il miglioramento che Paul Farry suggerisce, e il problema memoria / prestazioni che Christian.K sottolinea sono entrambi molto importanti.

Cosa ne pensi di questo:

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

L’ho trovato qui (nei commenti): http://sofit.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 }

per

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

Potresti:

 public IEnumerable FilterFiles(string path, params string[] exts) { return Directory .EnumerateFiles(path, "*.*") .Where(file => exts.Any(x => file.EndsWith(x, StringComparison.OrdinalIgnoreCase))); } 
  • Non dimenticare il nuovo .NET4 Directory.EnumerateFiles per un incremento delle prestazioni ( Qual è la differenza tra Directory.EnumerateFiles vs Directory.GetFiles? )
  • “IgnoreCase” dovrebbe essere più veloce di “ToLower” ( .EndsWith("aspx", StringComparison.OrdinalIgnoreCase) piuttosto che .ToLower().EndsWith("aspx") )

Ma il vero vantaggio di EnumerateFiles presenta quando dividi i filtri e unisci i risultati:

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

Diventa un po ‘più veloce se non è necessario trasformarli in glob (es. exts = new[] {"*.mp3", "*.jpg"} già).

Valutazione delle prestazioni basata sul seguente test LinqPad (nota: Perf ripete semplicemente il delegato 10000 volte) https://gist.github.com/zaus/7454021

(ripubblicato ed esteso da “duplicato” poiché tale domanda non richiedeva specificamente LINQ: Multiple file-extensions searchPattern per System.IO.Directory.GetFiles )

So che è una vecchia domanda, ma LINQ: (.NET40 +)

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

Un altro modo di usare Linq, ma senza dover restituire tutto e filtrarlo in memoria.

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

In realtà sono 2 chiamate a GetFiles() , ma penso che sia coerente con lo spirito della domanda e le restituisce in una enumerabile.

C’è anche una soluzione di discesa che sembra non avere memoria o prestazioni generali ed essere piuttosto elegante:

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

No. Prova quanto segue:

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

Tratto da: http://sofit.miximages.com/c%23/ppre codevar set = new HashSetstring { .mp3, .jpg” };

Poi

 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; 

Non posso usare. .Where metodo perché sto programmando in .NET Framework 2.0 (Linq è supportato solo in .NET Framework 3.5+).

Il codice qui sotto non è sensibile al maiuscolo / minuscolo (quindi verranno elencati anche .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 seguente funzione cerca su più pattern, separati da virgole. Puoi anche specificare un’esclusione, ad esempio: “! Web.config” cercherà tutti i file ed esclude “web.config”. I modelli possono essere mescolati.

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

Ho appena trovato un altro modo per farlo. Ancora nessuna operazione, ma la butto fuori per vedere cosa ne pensano gli altri.

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

Che dire

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

Crea le estensioni di una stringa, ad esempio “.mp3.jpg.wma.wmf”, quindi controlla se ciascun file contiene l’estensione desiderata. Funziona con .net 2.0 in quanto non 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 } } 

Il vantaggio di questo approccio è che puoi aggiungere o rimuovere estensioni senza modificare il codice, ad esempio aggiungere immagini png, basta scrivere 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 … Credo che tu debba fare tante chiamate quanti sono i tipi di file che vuoi.

Creerei una funzione io stesso prendendo un array su stringhe con le estensioni che mi servono e poi eseguo l’iterazione su quell’array facendo tutte le chiamate necessarie. Quella funzione restituirebbe un elenco generico dei file corrispondenti alle estensioni che avevo inviato.

Spero che sia d’aiuto.

in .NET 2.0 (senza 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() } 

Quindi usalo:

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

Ho avuto lo stesso problema e non sono riuscito a trovare la soluzione giusta, quindi ho scritto una funzione chiamata 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(); } 

Questa funzione chiamerà Directory.Getfiles() solo una volta.

Ad esempio chiama la funzione in questo modo:

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

EDIT: per ottenere un file con più estensioni utilizzare questo:

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

Ad esempio chiama la funzione in questo modo:

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

Mi chiedo perché ci siano così tante “soluzioni” pubblicate?

Se la mia comprensione della rookie su come funziona GetFiles è giusta, ci sono solo due opzioni e qualsiasi delle soluzioni sopra può essere ridotta a questi:

  1. GetFiles, quindi filtro: Veloce, ma un killer di memoria dovuto all’archiviazione del sovraccarico fino all’applicazione dei filtri

  2. Filtro mentre GetFiles: Più lento è il numero di filtri impostati, ma basso utilizzo della memoria come nessun sovraccarico viene memorizzato.
    Questo è spiegato in uno dei post di cui sopra con un benchmark impressionante: ogni opzione di filtro causa un’operazione separata GetFile in modo che la stessa parte dell’harddrive venga letta più volte.

A mio parere l’opzione 1) è migliore, ma l’utilizzo di SearchOption.AllDirectories su cartelle come C: \ userebbe enormi quantità di memoria.
Perciò creerò un sottoprocesso ricorsivo che attraversi tutte le sottocartelle usando l’opzione 1)

Ciò dovrebbe causare solo 1 operazione GetFiles su ciascuna cartella e quindi essere veloce (opzione 1), ma utilizzare solo una piccola quantità di memoria quando i filtri vengono applicati dopo ogni lettura delle sottocartelle -> il sovraccarico viene eliminato dopo ogni sottocartella.

Perfavore, correggimi se sbaglio. Sono come ho detto abbastanza nuovo alla programmazione, ma voglio approfondire la conoscenza delle cose per diventare finalmente bravo in questo 🙂

non so quale soluzione è meglio, ma io uso questo:

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

Se si utilizza VB.NET (o importato la dipendenza nel progetto C #), esiste effettivamente un metodo di convenienza che consente di filtrare per più estensioni:

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

In VB.NET è ansible accedervi tramite il My-namespace:

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

Sfortunatamente, questi metodi di convenienza non supportano una variante ponderata come Directory.EnumerateFiles() .

O puoi semplicemente convertire la stringa di estensioni in 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; } 

spero che questo aiuti qualcuno:

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