Using Directory.GetFiles with a regex in C#? - c#

I have this code:
string[] files = Directory.GetFiles(path, "......", SearchOption.AllDirectories)
What I want is to return only files which do NOT start with p_ and t_ and have the extension png or jpg or gif. How would I do this?

Directory.GetFiles doesn't support RegEx by default, what you can do is to filter by RegEx on your file list. Take a look at this listing:
Regex reg = new Regex(#"^^(?!p_|t_).*");
var files = Directory.GetFiles(yourPath, "*.png; *.jpg; *.gif")
.Where(path => reg.IsMatch(path))
.ToList();

You can't stick a Regex into the parameter, it's just a simple string filter. Try using LINQ to filter out afterwards instead.
var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
.Where(s => s.EndsWith(".jpg") || s.EndsWith(".png"))
.Where(s => s.StartsWith("p_") == false && s.StartsWith("t_") == false)

Try this code, searches every Drive as well:
DriveInfo[] drives = DriveInfo.GetDrives();
foreach (DriveInfo drive in drives)
{
if (drive.RootDirectory.Exists)
{
DirectoryInfo darr = new DirectoryInfo(drive.RootDirectory.FullName);
DirectoryInfo[] ddarr = darr.GetDirectories();
foreach (DirectoryInfo dddarr in ddarr)
{
if (dddarr.Exists)
{
try
{
Regex regx = new Regex(#"^(?!p_|t_)");
FileInfo[] f = dddarr.GetFiles().Where(path => regx.IsMatch(path));
List<FileInfo> myFiles = new List<FileInfo>();
foreach (FileInfo ff in f)
{
if (ff.Extension == "*.png " || ff.Extension == "*.jpg")
{
myFiles.Add(ff);
Console.WriteLine("File: {0}", ff.FullName);
Console.WriteLine("FileType: {0}", ff.Extension);
}
}
}
catch
{
Console.WriteLine("File: {0}", "Denied");
}
}
}
}
}

I just ran into this and here's how I handled it. It's in VB.net, but it should port over to C# pretty easily.
I needed to manipulate images in a folder that began with "king-". However, there were numerous filenames and patterns, so it was easiest for me to parse through all of them and match the regex as a string. I sorted them alphabetically because what I needed to do worked best if I did that.
The upshot is that you use the regular expression when you enumerate through the files themselves rather than trying to use it as a parameter.
Dim imgPath As String = Server.MapPath("~/images/")
Dim imgDir As New System.IO.DirectoryInfo(imgPath)
Dim RegexPath As String = "king-(.*)-count-\d{1,}\.jpg"
Dim RegX As New Regex(RegexPath)
Dim kingPics As List(Of String) = imgDir.EnumerateFiles("king-*.*").Select(Function(f) f.Name).ToList()
For Each pic As String In kingPics
Dim isMatch As Boolean = RegX.IsMatch(pic)
If isMatch Then
' I did my matching work here.
End If
Next

Related

Searching directory and 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll [duplicate]

In C# how can I search through a Folder and its Subfolders to find files that match a string value. My string value could be "ABC123" and a matching file might be ABC123_200522.tif. Can an Array collect these?
You're looking for the Directory.GetFiles method:
Directory.GetFiles(path, "*" + search + "*", SearchOption.AllDirectories)
If the matching requirements are simple, try:
string[] matchingFiles = System.IO.Directory.GetFiles( path, "*ABC123*" );
If they require something more complicated, you can use regular expressions (and LINQ):
string[] allFiles = System.IO.Directory.GetFiles( path, "*" );
RegEx rule = new RegEx( "ABC[0-9]{3}" );
string[] matchingFiles = allFiles.Where( fn => rule.Match( fn ).Success )
.ToArray();
DirectoryInfo di = new DirectoryInfo("c:/inetpub/wwwroot/demos");
FileInfo[] rgFiles = di.GetFiles("*.aspx");
you can pass in a second parameter for options. Also, you can use linq to filter the results even further.
check here for MSDN documentation
void DirSearch(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, sMatch))
{
lstFilesFound.Add(f);
}
DirSearch(d);
}
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
where sMatch is the criteria of what to search for.
From memory so may need tweaking
class Test
{
ArrayList matches = new ArrayList();
void Start()
{
string dir = #"C:\";
string pattern = "ABC";
FindFiles(dir, pattern);
}
void FindFiles(string path, string pattern)
{
foreach(string file in Directory.GetFiles(path))
{
if( file.Contains(pattern) )
{
matches.Add(file);
}
}
foreach(string directory in Directory.GetDirectories(path))
{
FindFiles(directory, pattern);
}
}
}
Adding to SLaks answer, in order to use the Directory.GetFiles method, be sure to use the System.IO namespace.

How can I find a file within any description of path?

I need find the specific file/folder on my hard drive.
For example i need find a file (do1.bat) and then store the path of the file. But i dont know where can it be stored, so i have to scan all hard drive.
How can i use C# for this?
A simple way would be
var results = Directory.GetFiles("c:\\", "do1.bat", SearchOption.AllDirectories);
This would recurse through all directory and collect all files named do1.bat. Unfortunatly this will not work on complete c:\ since it will throw exceptions if you don't have access to a directory, which surely will happen.
So this is a recursive version:
private static void FindFile(DirectoryInfo currentDirectory, string pattern, List<FileInfo> results)
{
try
{
results.AddRange(currentDirectory.GetFiles(pattern, SearchOption.TopDirectoryOnly));
foreach (DirectoryInfo dir in currentDirectory.GetDirectories("*", SearchOption.TopDirectoryOnly).Where(d => d.Name != "." && d.Name != ".."))
FindFile(dir, pattern, results);
}
catch
{
// probably no access to directory
}
}
This recurses through the directory tree and tries to get the files in a directory and then all subdirectories (except . and ..).
You can use it this way:
DirectoryInfo d = new DirectoryInfo("c:\\");
List<FileInfo> results = new List<FileInfo>();
FindFile(d, "do1.bat", results);
This will find all files named do1.bat in any subdirectory of C:\\ and enlist the FileInfos in the results list.
this should provide you a list of files, matching your search pattern
string[] Result = Directory.GetFiles(#"C:\", "do1.bat", SearchOption.AllDirectories);
Refer: https://msdn.microsoft.com/en-us/library/07wt70x2(v=vs.110).aspx
List<string> lstfilepaths = new List<string>();
public static void ProcessDirectory(string targetDirectory)
{
// Process the list of files found in the directory.
string [] fileEntries = Directory.GetFiles(targetDirectory);
foreach(string fileName in fileEntries) // included as per your logic
{
if(fileName == "do1.bat")
{
ProcessFile(fileName);
}
}
// Recurse into subdirectories of this directory.
string [] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
foreach(string subdirectory in subdirectoryEntries)
ProcessDirectory(subdirectory);
}
public static void ProcessFile(string path)
{
lstfilepaths.Add(path);
}
For one file:
public string FindFileByName(string fileName, string searchPath)
{
string resultPath = null;
DirectoryInfo directoryInWhichToSearch = new DirectoryInfo(searchPath);
FileInfo foundFile = directoryInWhichToSearch.GetFiles(fileName, SearchOption.AllDirectories)[0];
resultPath = foundFile.FullName;
return resultPath;
}
You can then use it like this:
string fileFullPath = FindFileByName("do1.bat", #"C:\");

Find all files in first sub directories

I have an application which searches in all directories behind Documents/GameLauncher/ Like this:
var foundApplications = Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/GameLauncher", "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".exe") || s.EndsWith(".lnk") || s.EndsWith(".url"));
This works fine but now I only want to find all the applications in the first sub directories of this folder. Like this:
GameLauncher/test/test.exe <--- find this file
GameLauncher/test/test/test.exe <--- Ignore this file
GameLauncher/hello/hello.exe <--- find this file
I have searched around and came up with this:
//Search for first sub directories of path
var folders = Directory.GetDirectories(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/GameLauncher");
IEnumerable<string> foundApplications;
//Use folders to find applications and add them to foundApplications
for (int i = 0; i < folders.Count(); i++)
{
foundApplications += Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/GameLauncher/" + folders[i], "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".exe") || s.EndsWith(".lnk") || s.EndsWith(".url"));
}
//Ends up with error "Use of unassigned local variable 'foundApplications'" when using = instead of += in the forloop above.
foreach (var application in foundApplications){
MessageBox.Show(application.ToString());
}
Does anyone have any tips to solve this problem or even a better way to find those files in the first sub directories of my GameLauncher folder?
Thanks for reading/helping.
Just don't use the "all" option if you don't want all, simple as that.
var path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
#"GameLauncher");
var includedExtensions = new HashSet<string> { ".exe", ".lnk", ".url" };
var files =
from dir in Directory.EnumerateDirectories(path)
from file in Directory.EnumerateFiles(dir)
let extension = Path.GetExtension(file)
where includedExtensions.Contains(extension)
select file;
You should be working with a list instead of an IEnumerable since it will grow dynamically.
var foundApplications = new List<string>();
var folders = Directory.GetDirectories(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/GameLauncher");
//Use folders to find applications and add them to foundApplications
for (int i = 0; i < folders.Count(); i++)
{
foundApplications.AddRange(Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/GameLauncher/" + folders[i], "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".exe") || s.EndsWith(".lnk") || s.EndsWith(".url").ToList());
}
foreach (var application in foundApplications){
MessageBox.Show(application.ToString());
}
If you want to append one IEnumerable to another you need to use Concat. You'll also have to initialize foundApplications to an empty IEnumerable.
var folderPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"GameLauncher");
var folders = Directory.GetDirectories(folderPath);
IEnumerable<string> foundApplications = Enumerable<string>.Empty;
//Use folders to find applications and add them to foundApplications
foreach(var subFolder in folders)
{
string path = Path.Combine(folderPath, subFolder);
foundApplications.Concat(
Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly)
.Where(s => s.EndsWith(".exe") || s.EndsWith(".lnk") || s.EndsWith(".url")));
}
foreach (var application in foundApplications){
MessageBox.Show(application.ToString());
}
Also I'm pretty sure you want to use SearchOption.TopDirectoryOnly not SearchOption.AllDirectories

How can recursively search directories with multiple wildcards?

Using C# (.NET), how can I search a file system given a directory search mask like this: (?)
\\server\Scanner\images\*Images\*\*_*
For example, I need to first find all top-level directories:
\\server\Scanner\images\Job1Images
\\server\Scanner\images\Job2Images
...then I need to procede further with the search mask:
\\server\Scanner\images\Job1Images\*\*_*
\\server\Scanner\images\Job2Images\*\*_*
This doesn't seem too complicated but I can't figure it out for the life of me...
As mentioned above, I'm using C# and .NET. The search can be trying to locate directories or files. (i.e. *.txt, or <*Directory>)
Like this:
Top Level Directories:
//get Top level
string[] TopLevel = Directory.GetDirectories(path);
And then you will have to do a resursive function of this folders using wildcard pattern,
for example:
// Only get subdirectories that begin with the letter "p."
string pattern = "p*";
string[] dirs = folder.GetDirectories(path, pattern);
I suggest you play with wildcards to get the array output and you will figure out
which is the best way, if using resursive function or directly quering paths.
Edit: Ahh, new functionality with .NET 4 so you don't have to do a recursive function (Thanks Matthew Brubaker)
IEnumerable<String> matchingFilePaths2 = System.IO.Directory.EnumerateFiles(#"C:\some folder to start in", filePatternToMatchOn, System.IO.SearchOption.AllDirectories);
First Answer:
//get all files that have an underscore - searches all folders under the start folder
List<String> matchingFilePaths = new List<string>();
String filePatternToMatchOn = "*_*";
FileUtilities.GetAllFilesMatchingPattern(#"C:\some folder to start in", ref matchingFilePaths, filePatternToMatchOn);
...
public static void GetAllFilesMatchingPattern(String pathToGetFilesIn, ref List<String> fullFilePaths, String searchPattern)
{
//get all files in current directory that match the pattern
String[] filePathsInCurrentDir = Directory.GetFiles(pathToGetFilesIn, searchPattern);
foreach (String fullPath in filePathsInCurrentDir)
{
fullFilePaths.Add(fullPath);
}
//call this method recursively for all directories
String[] directories = Directory.GetDirectories(pathToGetFilesIn);
foreach (String path in directories)
{
GetAllFilesMatchingPattern(path, ref fullFilePaths, searchPattern);
}
}
public static IEnumerable<string> GetImages()
{
//For each "*Image" directory
foreach (var jobFolder in Directory.EnumerateDirectories(#"\\server\Scanner\images", "*Images"))
{
//For each first level subdirectory
foreach (var jobSubFolder in Directory.EnumerateDirectories(jobFolder))
{
//Enumerate each file containing a '_'
foreach (var filePath in Directory.EnumerateFiles(jobSubFolder, "*_*", SearchOption.TopDirectoryOnly))
{
yield return filePath;
}
}
}
}
Only the files from the first level subdirectories of each "*Image" directory are enumerated.
Finally you can use it with:
foreach (var path in GetImages())
{
Console.WriteLine(path);
}
There is a C# procedure where you can search folder by path pattern with wildcards like * and ?.
Example if path pattern C:\Folder?*\Folder2 is passed to the procedru, then a list of folder path will be returned
C:\Folder1\A\Folder2
C:\FolderA\B\Folder2
...
and so on
static List<string> GetFoldersByPathPattern(string folderPathPattern)
{
List<string> directories = new List<string>();
directories.Add("");
string[] folderParts = folderPathPattern.Split(new char[] { '\\' }, StringSplitOptions.None);
foreach (string folderPart in folderParts)
{
if (folderPart.Contains('*') || folderPart.Contains('?'))
{
List<string> newDirectories = new List<string>();
foreach (string directory in directories)
{
foreach (string newDirectory in Directory.GetDirectories(directory, folderPart))
{
newDirectories.Add(newDirectory);
}
}
directories = newDirectories;
}
else
{
for (int i = 0; i < directories.Count(); i++)
{
directories[i] = directories[i] + folderPart + "\\";
}
}
}
return directories;
}

Exact file extension match with GetFiles()?

I'd like to retrieve a list of files whose extensions match a specified string exactly.
DirectoryInfo di = new DirectoryInfo(someValidPath);
List<FileInfo> myFiles = new List<FileInfo>();
foreach (FileInfo fi in di.GetFiles("*.txt"))
{
myFiles.Add(fi);
}
I get the files with extension *.txt but I also get files with the extension *.txtx, so what I've coded amounts to getting the files whose extension starts with txt.
This isn't what I want. Do I need to grab all of the filenames and do a regular expression match to "\\.txt$" (I think), or test each filename string with .EndsWith(".txt"), etc., to accomplish this?
Thanks!
Somewhat of a workaround, but you can filter out exact matches with the Where extesion method:
foreach (FileInfo fi in di.GetFiles("*.txt")
.Where(fi => string.Compare(".txt", fi.Extension, StringComparison.OrdinalIgnoreCase) == 0))
{
myFiles.Add(fi);
}
Note that this will make a case insensitive matching of the extension.
Using the AddRange feature of lists instead of doing the foreach loop and calling Add for each item returned by the expression below (which I save into the variable list).
var list = di.GetFiles("*.txt").Where(f => f.Extension == ".txt");
myFiles.AddRange(list);
I'm presuming you were just showing us a snippet of your code and myFiles already had values in it, if not, you could do instead.
List<FileInfo> myFiles = di.GetFiles("*.txt").Where(f => f.Extension == ".txt").ToList();
Regex might be overkill. Use the extension on FileInfo.
foreach (FileInfo fi in di.GetFiles("*.txt").Where(f => f.Extension == ".txt"))
{
myFiles.Add(fi);
}
Try this:
DirectoryInfo di = new DirectoryInfo(someValidPath);
List<FileInfo> myFiles =
(
from file in di.GetFiles("*.txt")
where file.Extension == ".txt"
select file
).ToList();
DirectoryInfo di = new DirectoryInfo(someValidPath);
List<FileInfo> myFiles = new List<FileInfo>();
foreach (FileInfo fi in di.GetFiles("*.txt"))
{
if (fi.Extension == ".txt")
myFiles.Add(fi);
}
Couldn't you just add an if and check the last four characters of the filename?
If you are using C# 2.0
Isn't easier ?
string fileExtensionFilter = "*.txt";
DirectoryInfo di = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
List<FileInfo> myFiles = new List<FileInfo>();
foreach (FileInfo fi in di.GetFiles(fileExtensionFilter))
{
if (fi.Extension == fileExtensionFilter.Substring(1)) myFiles.Add(fi);
}
I had a user-supplied pattern so many of the other answers didn't suit me. I ended up with this more general purpose solution:
public string[] GetFiles(string path, string pattern)
{
bool lastWildIsHook = false;
if(pattern.EndsWith("?"))
{
pattern = pattern.Substring(0, pattern.Length - 1);
lastWildIsHook = true;
}
var lastWildIndex = Math.Max(pattern.LastIndexOf("*"), pattern.LastIndexOf("?"));
var endsWith = pattern.Length > lastWildIndex ? pattern.Substring(lastWildIndex + 1) : pattern;
if(!lastWildIsHook)
return Directory.GetFiles(path, pattern).Where(p => p.EndsWith(endsWith)).ToArray();
else
return Directory.GetFiles(path, pattern).Where(p => p.EndsWith(endsWith) || p.Substring(0, p.Length - 1).EndsWith(endsWith)).ToArray();
}

Categories

Resources