Multiple file-extensions searchPattern for System.IO.Directory.GetFiles - c#
What is the syntax for setting multiple file-extensions as searchPattern on Directory.GetFiles()? For example filtering out files with .aspx and .ascx extensions.
// TODO: Set the string 'searchPattern' to only get files with
// the extension '.aspx' and '.ascx'.
var filteredFiles = Directory.GetFiles(path, searchPattern);
Update: LINQ is not an option, it has to be a searchPattern passed into GetFiles, as specified in the question.
var filteredFiles = Directory
.GetFiles(path, "*.*")
.Where(file => file.ToLower().EndsWith("aspx") || file.ToLower().EndsWith("ascx"))
.ToList();
Edit 2014-07-23
You can do this in .NET 4.5 for a faster enumeration:
var filteredFiles = Directory
.EnumerateFiles(path) //<--- .NET 4.5
.Where(file => file.ToLower().EndsWith("aspx") || file.ToLower().EndsWith("ascx"))
.ToList();
Directory.EnumerateFiles in MSDN
I like this method, because it is readable and avoids multiple iterations of the directory:
var allowedExtensions = new [] {".doc", ".docx", ".pdf", ".ppt", ".pptx", ".xls", ".xslx"};
var files = Directory
.GetFiles(folder)
.Where(file => allowedExtensions.Any(file.ToLower().EndsWith))
.ToList();
I believe there is no "out of the box" solution, that's a limitation of the Directory.GetFiles method.
It's fairly easy to write your own method though, here is an example.
The code could be:
/// <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 can only match a single pattern, but you can use Linq to invoke GetFiles with multiple patterns:
FileInfo[] fi = new string[]{"*.txt","*.doc"}
.SelectMany(i => di.GetFiles(i, SearchOption.AllDirectories))
.ToArray();
See comments section here:
http://www.codeproject.com/KB/aspnet/NET_DirectoryInfo.aspx
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();
Don't forget the new .NET4 Directory.EnumerateFiles for a performance boost (What is the difference between Directory.EnumerateFiles vs Directory.GetFiles?)
"IgnoreCase" should be faster than "ToLower"
Or, it may be faster to split and merge your globs (at least it looks cleaner):
"*.ext1;*.ext2".Split(';')
.SelectMany(g => Directory.EnumerateFiles(path, g))
.ToList();
I fear you will have to do somthing like this, I mutated the regex from here.
var searchPattern = new Regex(
#"$(?<=\.(aspx|ascx))",
RegexOptions.IgnoreCase);
var files = Directory.EnumerateFiles(path)
.Where(f => searchPattern.IsMatch(f))
.ToList();
The easy-to-remember, lazy and perhaps imperfect solution:
Directory.GetFiles(dir, "*.dll").Union(Directory.GetFiles(dir, "*.exe"))
I would use the following:
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: corrected due mismatch between Directory and DirectoryInfo
I would try to specify something like
var searchPattern = "as?x";
it should work.
A more efficient way of getting files with the extensions ".aspx" and ".ascx"
that avoids querying the file system several times and avoids returning a lot of undesired files, is to pre-filter the files by using an approximate search pattern and to refine the result afterwards:
var filteredFiles = Directory.GetFiles(path, "*.as?x")
.Select(f => f.ToLowerInvariant())
.Where(f => f.EndsWith("px") || f.EndsWith("cx"))
.ToList();
/// <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();
}
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);
}
Instead of the EndsWith function, I would choose to use the Path.GetExtension() method instead. Here is the full example:
var filteredFiles = Directory.EnumerateFiles( path )
.Where(
file => Path.GetExtension(file).Equals( ".aspx", StringComparison.OrdinalIgnoreCase ) ||
Path.GetExtension(file).Equals( ".ascx", StringComparison.OrdinalIgnoreCase ) );
or:
var filteredFiles = Directory.EnumerateFiles(path)
.Where(
file => string.Equals( Path.GetExtension(file), ".aspx", StringComparison.OrdinalIgnoreCase ) ||
string.Equals( Path.GetExtension(file), ".ascx", StringComparison.OrdinalIgnoreCase ) );
(Use StringComparison.OrdinalIgnoreCase if you care about performance: MSDN string comparisons)
You can do it like this
new DirectoryInfo(path).GetFiles().Where(Current => Regex.IsMatch(Current.Extension, "\\.(aspx|ascx)", RegexOptions.IgnoreCase)
look like this 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()));
}
#Daniel B, thanks for the suggestion to write my own version of this function. It has the same behavior as Directory.GetFiles, but supports regex filtering.
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();
}
I found it useful, so I thought I'd share.
c# version of #qfactor77's answer. This is the best way without 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);
now return filePath string array. In the beginning you need
using Microsoft.VisualBasic.FileIO;
using System.Collections.ObjectModel;
also you need to add reference to Microsoft.VisualBasic
I did a simple way for seach as many extensions as you need, and with no 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();
Working on .Net Standard 2.0.
var filtered = Directory.GetFiles(path)
.Where(file => file.EndsWith("aspx", StringComparison.InvariantCultureIgnoreCase) || file.EndsWith("ascx", StringComparison.InvariantCultureIgnoreCase))
.ToList();
Just would like to say that if you use FileIO.FileSystem.GetFiles instead of Directory.GetFiles, it will allow an array of wildcards.
For example:
Dim wildcards As String() = {"*.html", "*.zip"}
Dim ListFiles As List(Of String) = FileIO.FileSystem.GetFiles(directoryyouneed, FileIO.SearchOption.SearchTopLevelOnly, wildcards).ToList
(Sorry to write this as an answer, but I don't have privileges to write comments yet.)
Note that the FileIO.FileSystem.GetFiles() method from Microsoft.VisualBasic is just a wrapper to execute a search for each provided pattern and merge the results.
When checking the source from the .pbd file, you can see from this fragment FileSystem.FindPaths is executed for each pattern in the collection:
private static void FindFilesOrDirectories(
FileSystem.FileOrDirectory FileOrDirectory,
string directory,
SearchOption searchType,
string[] wildcards,
Collection<string> Results)
{
// (...)
string[] strArray = wildcards;
int index = 0;
while (index < strArray.Length)
{
string wildCard = strArray[index];
FileSystem.AddToStringCollection(Results, FileSystem.FindPaths(FileOrDirectory, directory, wildCard));
checked { ++index; }
}
// (...)
}
According to jonathan's answer (for 2 file extensions):
public static string[] GetFilesList(string dir) =>
Directory.GetFiles(dir, "*.exe", SearchOption.AllDirectories)
.Union(Directory.GetFiles(dir, "*.dll", SearchOption.AllDirectories)).ToArray();
Or for more file extensions (search in this folder and subfolders):
public static List<string> GetFilesList(string dir, params string[] fileExtensions) {
List<string> files = new List<string>();
foreach (string fileExtension in fileExtensions) {
files.AddRange(Directory.GetFiles(dir, fileExtension, SearchOption.AllDirectories));
}
return files;
}
List<string> files = GetFilesList("C:\\", "*.exe", "*.dll");
In 3250 files took to find 1890 files takes 0.6 second.
Related
Searching with System.IO.Directory.GetFiles and wildcards in path
I have a curious problem in a C#-program. I have some local folderpaths like "C:\test\AB_Systems\ELEGANCE\CB-DOC\live\M7-091.249.99.XX.01\extobjects". Now i want to search for PDF-files in the subfolder called "extobjects". Unfortunately there are many subfolders in the folder "live", which got a subfolder called "extobjects", so i thought it would be better to use a wildcard in the searchpath like that: "C:\test\AB_Systems\ELEGANCE\CB-DOC\live\*\extobjects" But this doesn't work. Is there a way do do this?
public static FileInfo[] findFile(String whereToSearch, String searchFor , String mode) { IEnumerable<FileInfo> files = null; if (mode.Equals("")) mode = "s"; if (searchFor.Equals("")) searchFor = "*"; if (mode.Equals("r") || mode.Equals("recursive")) { DirectoryInfo dir = new DirectoryInfo(whereToSearch); files = dir.EnumerateFiles(searchFor, searchOption: SearchOption.AllDirectories); } if (mode.Equals("s") || mode.Equals("specific")) { DirectoryInfo dir = new DirectoryInfo(whereToSearch); files = dir.EnumerateFiles(searchFor, searchOption: SearchOption.TopDirectoryOnly); } if (files != null) return files.ToArray<FileInfo>(); else return null; } That's an example how to do it. It's important to say that only the filename can contain a wildcard pattern like *. The Path can be given as where to start the search and by giving searchOption: searchOption.AllDirectories as an argument it will go through all sub-directories of the entry path. You will receive an Array of FileInfo which objects that contain the the path and more information.
You can use Linq like this: var files = Directory .EnumerateDirectories(#"C:\test\AB_Systems\ELEGANCE\CB-DOC\live", "extobjects", SearchOption.AllDirectories) .SelectMany(x => Directory.EnumerateFiles(x, "*pdf", SearchOption.TopDirectoryOnly)) .ToArray();
I'd choose a solution exactly what BugFinder proposed, you could optimize the following foreach-loop into a LINQ query if your .NET target supports it. // Itterate subdirectories of the live folder foreach (var subDir in Directory.GetDirectories(#"C:\test\AB_Systems\ELEGANCE\CB-DOC\live")) { // Check if path to extobjects exists var extObjects = Path.Combine(subDir, "extobjects"); if (Directory.Exists(extObjects)) { var pdfFiles = Directory.GetFiles(extObjects, "*").Where(x=>x.EndsWith(".pdf")); // Do something with the pdf file paths } }
Getting all files matching one of many extensions using System.IO.Directory
I'm trying to get all files from a directory that are one of these extensions: .aif, .wav, .mp3, or .ogg. Can I somehow combine these in a searchpattern, or do I have to iterate through all files once per extension? This is what I'd like: foreach (string filePath in Directory.GetFiles(pathRoot + "/Music/" + path, "*.mp3" || "*.aif" || "*.wav" || "*.ogg")) { //Do stuff }
If you need to check only for extensions then easiest solution I can think of is to get all files and compare extension with list: var extList = new string[] { ".mp3", ".aif", ".wav", ".ogg" }; var files = Directory.GetFiles(pathRoot + "/Music/" + path, "*.*") .Where(n => extList.Contains(System.IO.Path.GetExtension(n), StringComparer.OrdinalIgnoreCase)) .ToList();
There is no method to search for multiple patterns but you can write one: private string[] GetFiles(string path, params string[] searchPatterns) { var filePaths = new List<string>(); foreach (var searchPattern in searchPatterns) { filePaths.AddRange(Directory.GetFiles(path, searchPattern)); } filePaths.Sort(); return filePaths.ToArray(); } You can now call that where you would originally have called Directory.GetFiles and pass multiple patterns.
How to check for file names in a folder
I would like to be able to iterate through the name of some image files in a folder using c#. So for intance I have a folder named image and contains the following images image dog.jpg cat.jpg horse.jpg I want to be able to go through the names and be able to say if(filename == dog.jpg) return true else return false Something of that nature Thank you
You should use the static Exists method on System.IO.File. return System.IO.File.Exists("dog.jpg") Since the method returns a boolean, there is no need for the if statement in the example you gave. You can also use a bit of Linq magic to determine if a file exists in a folder structure, like this: var dir = new System.IO.DirectoryInfo(startFolder); var fileList = dir.GetFiles("*.*", System.IO.SearchOption.AllDirectories); bool fileExists = fileList.Any(f => f.FullName == "dog.jpg"); or even shorter: return System.IO.Directory .GetFiles(#"c:\myfolder", "dog.jpg", SearchOption.AllDirectories) .Any(); which would search the folder specified and all subfolder with the pattern "dog.jpg". The Any() extension method simply checks whether the IEnumerable contains any items. I think this is the most efficient way of doing this (based on gut feeling).
From http://weblogs.asp.net/israelio/archive/2004/06/23/162913.aspx Just insert your if in the "// do something with filename" area: // How much deep to scan. (of course you can also pass it to the method) const int HowDeepToScan=4; public static void ProcessDir(string sourceDir, int recursionLvl) { if (recursionLvl<=HowDeepToScan) { // Process the list of files found in the directory. string [] fileEntries = Directory.GetFiles(sourceDir); foreach(string fileName in fileEntries) { // do something with fileName Console.WriteLine(fileName); } // Recurse into subdirectories of this directory. string [] subdirEntries = Directory.GetDirectories(sourceDir); foreach(string subdir in subdirEntries) // Do not iterate through reparse points if ((File.GetAttributes(subdir) & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint) ProcessDir(subdir,recursionLvl+1); } }
get all the files string[] filePaths = Directory.GetFiles(#"c:\yourfolder\"); and iterate through it
use Directory.GetFiles() foreach(var file in (myDir.GetFiles("*.jpg") { if(file.Name == "dog.jpg") return true; }
var files = System.IO.Directory.GetFiles("directory", "*.jpg"); foreach (var item in files) { if (System.IO.Path.GetFileName(item) == "dog.jpg") { // File found. } }
DirectoryInfo di = new DirectoryInfo("c:\\Images"); var files = di.GetFiles("*.jpg"); foreach (var fileInfo in files) { if (fileInfo.Name == "dog.jpg") return true; } return false;
Sorting the result of Directory.GetFiles in C#
I have this code to list all the files in a directory. class GetTypesProfiler { static List<Data> Test() { List<Data> dataList = new List<Data>(); string folder = #"DIRECTORY"; Console.Write("------------------------------------------\n"); var files = Directory.GetFiles(folder, "*.dll"); Stopwatch sw; foreach (var file in files) { string fileName = Path.GetFileName(file); var fileinfo = new FileInfo(file); long fileSize = fileinfo.Length; Console.WriteLine("{0}/{1}", fileName, fileSize); } return dataList; } static void Main() { ... } } I need to print out the file info based on file size or alphabetical order. How can I sort the result from Directory.GetFiles()?
Very easy with LINQ. To sort by name, var sorted = Directory.GetFiles(".").OrderBy(f => f); To sort by size, var sorted = Directory.GetFiles(".").OrderBy(f => new FileInfo(f).Length);
To order by date: (returns an enumerable of FileInfo): Directory.GetFiles(folder, "*.dll").Select(fn => new FileInfo(fn)). OrderBy(f => f.Length); or, to order by name: Directory.GetFiles(folder, "*.dll").Select(fn => new FileInfo(fn)). OrderBy(f => f.Name); Making FileInfo instances isn't necessary for ordering by file name, but if you want to apply different sorting methods on the fly it's better to have your array of FileInfo objects in place and then just OrderBy them by Length or Name property, hence this implementation. Also, it looks like you are going to create FileInfo anyway, so it's better to have a collection of FileInfo objects either case. Sorry I didn't get it right the first time, should've read the question and the docs more carefully.
You can use LINQ if you like, on a FileInfo object: var orderedFiles = Directory.GetFiles("").Select(f=> new FileInfo(f)).OrderBy(f=> f.CreationTime)
try this, it works for me [System.Runtime.InteropServices.DllImport("Shlwapi.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] private static extern int StrCmpLogicalW(string psz1, string psz2); DirectoryInfo di = new DirectoryInfo(path); FileInfo[] arrFi = di.GetFiles("*.*"); Array.Sort(arrFi, delegate(FileInfo x, FileInfo y) { return StrCmpLogicalW(x.Name, y.Name); });
This works if you only need to sort by file name and the file title supports the ascending or descending logical order.I add variables to have a bit more control of the source and search pattern. Using Dir = System.IO; string Source = yourVariable; string SearchPattern = yourVariable; Dir.Directory.GetFiles(Source, SearchPattern, Dir.SearchOption.AllDirectories).OrderBy(s => s).ToList();
// Getting Directory object DirectoryInfo directoryInfo = new DirectoryInfo(folderName); // getting files for this folder FileInfo[] files = directoryInfo.GetFiles(); // Sorting using the generic Array.Sort function based on Names comparison Array.Sort(files, delegate (FileInfo x, FileInfo y) { return String.Compare(x.Name, y.Name); }); // Sorting using the generic Array.Sort function based on the creation date of every folder Array.Sort(files, delegate (FileInfo x, FileInfo y) { return DateTime.Compare(x.CreationTime, y.CreationTime); }); Array Sort
Can you call Directory.GetFiles() with multiple filters?
I am trying to use the Directory.GetFiles() method to retrieve a list of files of multiple types, such as mp3's and jpg's. I have tried both of the following with no luck: Directory.GetFiles("C:\\path", "*.mp3|*.jpg", SearchOption.AllDirectories); Directory.GetFiles("C:\\path", "*.mp3;*.jpg", SearchOption.AllDirectories); Is there a way to do this in one call?
For .NET 4.0 and later, var files = Directory.EnumerateFiles("C:\\path", "*.*", SearchOption.AllDirectories) .Where(s => s.EndsWith(".mp3") || s.EndsWith(".jpg")); For earlier versions of .NET, var files = Directory.GetFiles("C:\\path", "*.*", SearchOption.AllDirectories) .Where(s => s.EndsWith(".mp3") || s.EndsWith(".jpg")); edit: Please read the comments. The improvement that Paul Farry suggests, and the memory/performance issue that Christian.K points out are both very important.
How about this: 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(); } I found it here (in the comments): http://msdn.microsoft.com/en-us/library/wz42302f.aspx
If you have a large list of extensions to check you can use the following. I didn't want to create a lot of OR statements so i modified what lette wrote. string 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 }
for var exts = new[] { "mp3", "jpg" }; You could: public IEnumerable<string> FilterFiles(string path, params string[] exts) { return Directory .EnumerateFiles(path, "*.*") .Where(file => exts.Any(x => file.EndsWith(x, StringComparison.OrdinalIgnoreCase))); } Don't forget the new .NET4 Directory.EnumerateFiles for a performance boost (What is the difference between Directory.EnumerateFiles vs Directory.GetFiles?) "IgnoreCase" should be faster than "ToLower" (.EndsWith("aspx", StringComparison.OrdinalIgnoreCase) rather than .ToLower().EndsWith("aspx")) But the real benefit of EnumerateFiles shows up when you split up the filters and merge the results: public IEnumerable<string> FilterFiles(string path, params string[] exts) { return exts.Select(x => "*." + x) // turn into globs .SelectMany(x => Directory.EnumerateFiles(path, x) ); } It gets a bit faster if you don't have to turn them into globs (i.e. exts = new[] {"*.mp3", "*.jpg"} already). Performance evaluation based on the following LinqPad test (note: Perf just repeats the delegate 10000 times) https://gist.github.com/zaus/7454021 ( reposted and extended from 'duplicate' since that question specifically requested no LINQ: Multiple file-extensions searchPattern for System.IO.Directory.GetFiles )
I know it's old question but LINQ: (.NET40+) var files = Directory.GetFiles("path_to_files").Where(file => Regex.IsMatch(file, #"^.+\.(wav|mp3|txt)$"));
There is also a descent solution which seems not to have any memory or performance overhead and be quite elegant: string[] filters = new[]{"*.jpg", "*.png", "*.gif"}; string[] filePaths = filters.SelectMany(f => Directory.GetFiles(basePath, f)).ToArray();
Another way to use Linq, but without having to return everything and filter on that in memory. var files = Directory.GetFiles("C:\\path", "*.mp3", SearchOption.AllDirectories).Union(Directory.GetFiles("C:\\path", "*.jpg", SearchOption.AllDirectories)); It's actually 2 calls to GetFiles(), but I think it's consistent with the spirit of the question and returns them in one enumerable.
Let var set = new HashSet<string>( new[] { ".mp3", ".jpg" }, StringComparer.OrdinalIgnoreCase); // ignore case var dir = new DirectoryInfo(path); Then dir.EnumerateFiles("*.*", SearchOption.AllDirectories) .Where(f => set.Contains(f.Extension)); or from file in dir.EnumerateFiles("*.*", SearchOption.AllDirectories) from ext in set // makes sense only if it's just IEnumerable<string> or similar where String.Equals(ext, file.Extension, StringComparison.OrdinalIgnoreCase) select file;
Nope. Try the following: List<string> _searchPatternList = new List<string>(); ... List<string> fileList = new List<string>(); 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 ) { ...; } Taken from: http://blogs.msdn.com/markda/archive/2006/04/20/580075.aspx
I can't use .Where method because I'm programming in .NET Framework 2.0 (Linq is only supported in .NET Framework 3.5+). Code below is not case sensitive (so .CaB or .cab will be listed too). 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); } }
List<string> FileList = new List<string>(); DirectoryInfo di = new DirectoryInfo("C:\\DirName"); IEnumerable<FileInfo> fileList = di.GetFiles("*.*"); //Create the query IEnumerable<FileInfo> 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); }
in .NET 2.0 (no Linq): public static List<string> GetFilez(string path, System.IO.SearchOption opt, params string[] patterns) { List<string> filez = new List<string>(); foreach (string pattern in patterns) { filez.AddRange( System.IO.Directory.GetFiles(path, pattern, opt) ); } // filez.Sort(); // Optional return filez; // Optional: .ToArray() } Then use it: 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();
If you are using VB.NET (or imported the dependency into your C# project), there actually exists a convenience method that allows to filter for multiple extensions: Microsoft.VisualBasic.FileIO.FileSystem.GetFiles("C:\\path", Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, new string[] {"*.mp3", "*.jpg"}); In VB.NET this can be accessed through the My-namespace: My.Computer.FileSystem.GetFiles("C:\path", FileIO.SearchOption.SearchAllSubDirectories, {"*.mp3", "*.jpg"}) Unfortunately, these convenience methods don't support a lazily evaluated variant like Directory.EnumerateFiles() does.
The following function searches on multiple patterns, separated by commas. You can also specify an exclusion, eg: "!web.config" will search for all files and exclude "web.config". Patterns can be mixed. 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<Thread> workers = new List<Thread>(); List<string> files = new List<string>(); 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(); } Usage: foreach (string file in FindFiles(#"D:\628.2.11", #"!*.config, !*.js", SearchOption.AllDirectories)) { Console.WriteLine(file); }
What about 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<string> filesAll = new List<string>(totalArraySizeAll); filesAll.AddRange(filesPNG); filesAll.AddRange(filesJPG); filesAll.AddRange(filesJPEG);
Just found an another way to do it. Still not one operation, but throwing it out to see what other people think about it. 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; }
I wonder why there are so many "solutions" posted? If my rookie-understanding on how GetFiles works is right, there are only two options and any of the solutions above can be brought down to these: GetFiles, then filter: Fast, but a memory killer due to storing overhead untill the filters are applied Filter while GetFiles: Slower the more filters are set, but low memory usage as no overhead is stored.This is explained in one of the above posts with an impressive benchmark: Each filter option causes a seperate GetFile-operation so the same part of the harddrive gets read several times. In my opinion Option 1) is better, but using the SearchOption.AllDirectories on folders like C:\ would use huge amounts of memory. Therefor i would just make a recursive sub-method that goes through all subfolders using option 1) This should cause only 1 GetFiles-operation on each folder and therefor be fast (Option 1), but use only a small amount of memory as the filters are applied afters each subfolders' reading -> overhead is deleted after each subfolder. Please correct me if I am wrong. I am as i said quite new to programming but want to gain deeper understanding of things to eventually become good at this :)
Here is a simple and elegant way of getting filtered files var allowedFileExtensions = ".csv,.txt"; var files = Directory.EnumerateFiles(#"C:\MyFolder", "*.*", SearchOption.TopDirectoryOnly) .Where(s => allowedFileExtensions.IndexOf(Path.GetExtension(s)) > -1).ToArray();
Make the extensions you want one string i.e ".mp3.jpg.wma.wmf" and then check if each file contains the extension you want. This works with .net 2.0 as it does not use 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 } } The advantage with this approach is you can add or remove extensions without editing the code i.e to add png images, just write myExtensions=".jpg.mp3.png".
/// <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(); }
Nop... I believe you have to make as many calls as the file types you want. I would create a function myself taking an array on strings with the extensions I need and then iterate on that array making all the necessary calls. That function would return a generic list of the files matching the extensions I'd sent. Hope it helps.
I had the same problem and couldn't find the right solution so I wrote a function called GetFiles: /// <summary> /// Get all files with a specific extension /// </summary> /// <param name="extensionsToCompare">string list of all the extensions</param> /// <param name="Location">string of the location</param> /// <returns>array of all the files with the specific extensions</returns> public string[] GetFiles(List<string> extensionsToCompare, string Location) { List<string> files = new List<string>(); foreach (string file in Directory.GetFiles(Location)) { if (extensionsToCompare.Contains(file.Substring(file.IndexOf('.')+1).ToLower())) files.Add(file); } files.Sort(); return files.ToArray(); } This function will call Directory.Getfiles() only one time. For example call the function like this: string[] images = GetFiles(new List<string>{"jpg", "png", "gif"}, "imageFolder"); EDIT: To get one file with multiple extensions use this one: /// <summary> /// Get the file with a specific name and extension /// </summary> /// <param name="filename">the name of the file to find</param> /// <param name="extensionsToCompare">string list of all the extensions</param> /// <param name="Location">string of the location</param> /// <returns>file with the requested filename</returns> public string GetFile( string filename, List<string> 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 ""; } For example call the function like this: string image = GetFile("imagename", new List<string>{"jpg", "png", "gif"}, "imageFolder");
Using GetFiles search pattern for filtering the extension is not safe!! For instance you have two file Test1.xls and Test2.xlsx and you want to filter out xls file using search pattern *.xls, but GetFiles return both Test1.xls and Test2.xlsx I was not aware of this and got error in production environment when some temporary files suddenly was handled as right files. Search pattern was *.txt and temp files was named *.txt20181028_100753898 So search pattern can not be trusted, you have to add extra check on filenames as well.
Or you can just convert the string of extensions to String^ vector <string> 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<String^>^files = Directory::GetFiles(path,ext); Console::WriteLine(ext); cout << " " << (files->Length) << endl; }
i don t know what solution is better, but i use this: String[] ext = "*.ext1|*.ext2".Split('|'); List<String> files = new List<String>(); foreach (String tmp in ext) { files.AddRange(Directory.GetFiles(dir, tmp, SearchOption.AllDirectories)); }
you can add this to your project public static class Collectables { public static List<System.IO.FileInfo> FilesViaPattern(this System.IO.DirectoryInfo fldr, string pattern) { var filter = pattern.Split(" "); return fldr.GetFiles( "*.*", System.IO.SearchOption.AllDirectories) .Where(l => filter.Any(k => l.Name.EndsWith(k))).ToList(); } } then use it anywhere like this new System.IO.DirectoryInfo("c:\\test").FilesViaPattern("txt doc any.extension");