How to search for Files using GetFiles method (multiple criteria..) - c#

The code below obviously searches a directory for Files that contain the word "FINAL" but what I'm wondering is can I add to its search criteria? I have a Well_Name and Actual_Date strings that I would like to search for in the File names in addition to the "FINAL" word. Thoughts? Thanks in advance.
DirectoryInfo myDir = new DirectoryInfo("C://DWGs");
var files = myDir.GetFiles("FINAL");
//Can I do something like this to add to my search criteria?
var files = myDir.GetFiles("FINAL" +
drow["Well_Name"].ToString() +
drow["Actual_Date"]);

var files = myDir.GetFileInfo()
.Where(f => f.FileName.Contains("FINAL") ||
f.FileName.Contains(drow["Well_Name"].ToString()) ||
f.FileName.Contains(drow["Actual_Date"]));
Since GetFiles() returns an Enumerable Collection of FileInfo you can just check all of the file names for the criteria that you want.
If you want to get really generic on this you could write a function that looks like this
public IEnumerable<FileInfo> addCriteria(IEnumerable<FileInfo> FileList,
List<String> searchCriteria)
{
var newFileList = FileList;
foreach(String criteria in searchCriteria)
{
newFileList = newFileList.Where(f => f.FileName.Contains(criteria).AsQueryable();
}
return newFileList.AsEnumerable();
}

GetFiles method does not support multiple search criteria, but there is a simple way around this limitation. Run a getFile for each file extension, and then "merge" returned arrays into a List<>. Then use a List's ToArray method to "convert" a List back to an Array.
I used this approach, and it works for me
The code is below (do not forget to reference "using System.Collections.Generic;" namespace):
// Get the DirectoryInfo and FileInfo objects for aspx and html files.
FileInfo[] files_aspx = dir.GetFiles("*.aspx");
FileInfo[] files_html = dir.GetFiles("*.html");
List<FileInfo> files = new List<FileInfo>();
files.AddRange(files_aspx);
files.AddRange(files_html);
files.ToArray();

Related

How to Remove Directories From EnumerateFiles?

So I'm working on a program that will list all the files in a directory. Pretty simple. Basically, when I do this: List<string> dirs = new List<string>(Directory.EnumerateFiles(target));, I don't want it to include the directory and all. Just the file name. When I run my code;
List<string> dirs = new List<string>(Directory.EnumerateFiles(target));
Console.WriteLine($"Folders and files in this directory:\n");
foreach (string i in dirs) {
Console.WriteLine($"> {i}");
}
it gives me the following:
C:\Users\Camden\Desktop\Programming\Visual Studio\C#\DirectoryManager\DirectoryManager\bin\Debug\DirectoryManager.exe
I just want the DirectoryManager.exe part, so I looked it up and I found that you can replace strings inside of strings. Like so: i.Replace(target, "");. However, this isn't doing anything, and it's just running like normal. Why isn't it replacing, and how should I instead do this?
Use methods from the System.IO.Path class.
var fullfile = #"C:\Users\Camden\Desktop\Programming\Visual Studio\C#\DirectoryManager\DirectoryManager\bin\Debug\DirectoryManager.exe";
var fileName = Path.GetFileName(fullfile); // DirectoryManager.exe
var name = Path.GetFileNameWithoutExtension(fullfile); // DirectoryManager
The simplest way is to use the Select IEnumerable extension
(you need to have a using Linq; at the top of your source code file)
List<string> files = new List<string>(Directory.EnumerateFiles(target)
.Select(x => Path.GetFileName(x)));
In this way the sequence of files retrieved by Directory.EnumerateFiles is passed, one by one, to the Select method where each fullfile name (x) is passed to Path.GetFileName to produce a new sequence of just filenames.
This sequence is then returned as a parameter to the List constructor.
And about your question on the Replace method. Remember that the Replace method doesn't change the string that you use to call the method, but returns a new string with the replacement executed. In NET strings are immutable.
So if you want to look at the replacement you need
string justFileName = i.Replace(target, "");
An alternative to using Directory.EnumerateFiles, would be DirectoryInfo.EnumerateFiles. This method returns an IEnumerable<FileInfo>. You can then make use of the FileInfo.Name property of each of the returned objects. Your code would then become:
var files = new DirectoryInfo(target).EnumerateFiles();
Console.WriteLine("Files in this directory:\n");
foreach (FileInfo i in files) {
Console.WriteLine($"> {i.Name}");
}
For just the list of file names:
List<string> fileNames = new DirectoryInfo(target).EnumerateFiles().Select(f => f.Name).ToList();
Alternatively, if you want both files and directories, you can use EnumerateFileSystemInfos. If you need to know if you have a file vs a directory you can query the Attributes property and compare it to the FileAttributes flags enumeration.
var dirsAndFiles = new DirectoryInfo(target).EnumerateFileSystemInfos();
Console.WriteLine("Folders and files in this directory:\n");
foreach (var i in dirsAndFiles) {
var type = (i.Attributes & FileAttributes.Directory) == FileAttributes.Directory ? "Directory" : "File";
Console.WriteLine($"{type} > {i.Name}");
}
The FileSystemInfo.Name property will return either the file's name (in case of a file) or the last directory in the hierarchy (for a directory)--so just the subdirectory name and not the full path ("sub" instead of "c:\sub").

How to search a directory for files that begin with something then get the one that was modified most recently

What I want to do is search/scan a directory for multiple files beginning with something, then get the file that was last modified most recently. For example, I want to search the directory Prefetch for files that begin with "apple", "pear", and "orange". These files may not exist, but if they do, and say there are files that begin with apple and files that begin with pear, out of all of those files, I want to get the one that was modified most recently. The code below allows me do to this but search only 1 thing.
DirectoryInfo prefetch = new DirectoryInfo("c:\\Windows\\Prefetch");
FileInfo[] apple = prefetch.GetFiles("apple*");
if (apple.Length == 0)
// Do something
else
{
double lastused = DateTime.Now.Subtract(
apple.OrderByDescending(x => x.LastWriteTime)
.FirstOrDefault().LastWriteTime).TotalMinutes;
int final = Convert.ToInt32(lastused);
}
Basically, how can I make that code search 'apple', 'pear' etc. instead of just apple? I don't know if you can modify the code above to do that or if you have to change it completely. I've been trying to figure this out for hours and can't do it.
As explained in my comments you can't use DirectoryInfo.GetFiles to return list of FileInfo with so different patterns. Just one pattern is supported.
As others as already shown, you can prepare a list of patterns and then call in a loop the GetFiles on each pattern.
However, I would show you the same approach, but done with just one line of code in Linq.
List<string> patterns = new List<string> { "apple*", "pear*", "orange*" };
DirectoryInfo prefetch = new DirectoryInfo(#"c:\Windows\Prefetch");
var result = patterns.SelectMany(x => prefetch.GetFiles(x))
.OrderByDescending(k => k.LastWriteTime)
.FirstOrDefault();
Now, result is a FileInfo with the most recent update. Of course, if no files matches the three patterns, then result will be null. A check before using that variable is mandatory.
You could create a set of files that match the prefixes then check the date of those files, something like (not tested):
List<string> files=new List<string>();
foreach(var str in prefixes)
files.AddRange(dirInfo.GetFiles(str));
return (from d in (from name in files select File.GetLastAccessTime(name)) orderby d descending).FirstOrDefault();
prefixes is the list of search patterns, and dirInfo is a DirectoryInfo object.
You can iterate over a list
List<string> patterns = new List<string> { "apple*", "pear*", "orange*" };
DirectoryInfo prefetch = new DirectoryInfo("c:\\Windows\\Prefetch");
foreach (var pattern in patterns) {
FileInfo[] files = prefetch.GetFiles(pattern);
var lastAccessed = files.OrderByDescending(x => x.LastAccessTime).FirstOrDefault();
if (lastAccessed != null) {
var minutes = DateTime.Now.Subtract(lastAccessed.LastAccessTime).TotalMinutes;
}
}

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

Directory.GetFiles() returns full path

I want to return the files that are images, inside a particular directory. I want to create the image path like this
string[] ImageNames = Directory.GetFiles(path);
string tds="";
for (int i = 0; i < ImageNames.Length; i++)
{
tds += "<tr> <td> <img href=/Articles/ArticleImageStore/'" + ImageNames[i] + "' width='64' height='64'></img></tr> </td>";
}
but it returns the physical path of the file on the disk. How should I do this??
You can use Path.GetFileName:
string[] ImageNames = Directory.GetFiles(path)
.Select(p => Path.GetFileName(p)).ToArray();
This will produce a list with only the names of the files.
Rather than using the Directory class I would use DirectoryInfo then you can do this;
string[] fNames = new DirectoryInfo(dirPath).GetFiles("*.png").Select(x => x.FileName).ToArray();
The DirectoryInfo version of GetFiles returns FileInfo objects rather than the file paths as strings so you can do a lot more the with the results. I happen to have a select which sort of nullifies that by just projecting a the FileName for each FileInfo instance returned by GetFiles but if you needed to do more with the files you could remove that then loop over the FileInfo objects.
Also, I'm using an overload that has a pattern which will make it easy to ignore your non image files.
DirectoryInfo docs; http://msdn.microsoft.com/en-us/library/8he88b63.aspx

How to read File names recursively from subfolder using LINQ

How to read file name with dll extension from a directory and from its subfolders recursively using LINQ or LAMBDA expression.
Now i'm using Nested for-each loop to do this.
Is there any way to do this using LINQ or LAMBDA expression?
You don't need to use LINQ to do this - it's built into the framework:
string[] files = Directory.GetFiles(directory, "*.dll",
SearchOption.AllDirectories);
or if you're using .NET 4:
IEnumerable<string> files = Directory.EnumerateFiles(directory, "*.dll",
SearchOption.AllDirectories);
To be honest, LINQ isn't great in terms of recursion. You'd probably want to write your own general-purpose recursive extension method. Given how often this sort of question is asked, I should really do that myself some time...
this returns just file names+extensions:
DirectoryInfo di = new DirectoryInfo(#"d:\somewhere\");
var q = from i in di.GetFiles("*.dll", SearchOption.AllDirectories)
select i.Name;
this returns just file names without extensions:
DirectoryInfo di = new DirectoryInfo(#"d:\somewhere\");
var q = from i in di.GetFiles("*.dll", SearchOption.AllDirectories)
select System.IO.Path.GetFileNameWithoutExtension(i.Name);
If you really want to do it with a recursive lambda expression here you go:
Action<string, List<string>> discoverFiles = null;
discoverFiles = new Action<string, List<string>>((dir, list) =>
{
try
{
foreach (var subDir in Directory.GetDirectories(dir))
discoverFiles(string.Concat(subDir), list);
foreach (var dllFile in Directory.GetFiles(dir, "*.dll"))
{
var fileNameOnly = Path.GetFileName(dllFile);
if (!list.Contains(fileNameOnly))
list.Add(fileNameOnly);
}
}
catch (IOException)
{
// decide what to do here
}
});
// usage:
var targetList = new List<string>();
discoverFiles("c:\\MyDirectory", targetList);
foreach (var item in targetList)
Debug.WriteLine(item);
Note: this is probably several times slower (and way harder to read/debug/maintain) than the previous answers, but it does not stop if there is an I/O exception somewhere.
IEnumerable<string> filenames = Directory.GetFiles(searchDirectory, "*.dll",
SearchOption.AllDirectories)
.Select(s => Path.GetFileName(s));
Directory.GetFiles() returns the full path of files that match the specified search pattern in the specified directory. Select projects each element of fullpath sequence into a new form, only the filename.
Reading files and directories is usually done with classes situated in the System.IO namespace. So the first step would consist into getting all the files that you need to read using the Directory.EnumerateFiles method and then for each file that corresponds to your search criteria read the contents using for example the File.ReadAllBytes method.

Categories