How to EnumerateFiles with all subdirectories with C# DirectoryInfo? - c#

I found this code that gets an array of files out of a DirectoryInfo :
FileInfo[] fileInfoArray = di.EnumerateFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
But it only searches the direct children of the path of DirectoryInfo. i.e., it does not include grandchildren.
I guess I need to add SearchOption.AllDirectories parameter to somewhere, but where?
I tried :
di.EnumerateFiles(SearchOption.AllDirectories).Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
But it yields an error.
So how do I search with a pattern, including all subdirectories ?
Thanks for any help !

Look at the overloads of DirectoryInfo.EnumerateFiles - there's no overload taking just a SearchOption, but you can give a string and a SearchOption:
var files = di.EnumerateFiles("*", SearchOption.AllDirectories)
.Where(f => extensions.Contains(f.Extension.ToLower()))
.ToArray();

Related

DirectoryInfo.GetFiles with multiple filters

I am trying to get a list of FileInfo objects that satisfy multiple filters.
Every suggestion I have seen uses array of file names/paths instead of FileInfo:
var files = Directory.GetFiles(sLogPath, "*.*", SearchOption.TopDirectoryOnly)
.Where(s => s.StartsWith("abc", StringComparison.CurrentCultureIgnoreCase) || s.StartsWith("def", StringComparison.CurrentCultureIgnoreCase));
What I am trying to get is:
DirectoryInfo di = new DirectoryInfo(sLogPath);
var files = di.GetFiles(<same filter as above>);
But it looks like I can only do something like:
var files = di.GetFiles("*_" + dateStr + ".log");
Based on your comment to me on your question, it looks like you want to filter on file names, but get the FileInfos that correspond to these names.
You can do something like this
var di = new DirectoryInfo(sLogPath);
var files = di
.GetFiles("*.*", SearchOption.TopDirectoryOnly)
.Where(x => x.Name.StartsWith("abc", StringComparison.CurrentCultureIgnoreCase)
|| x.Name.StartsWith("def", StringComparison.CurrentCultureIgnoreCase))
.ToList();
We're using the Name property in the filter and working with the FileInfo[] array returned by DirectoryInfo.GetFiles().

How to filter files with date from a folder in C#

I have c# code to get the pdf files from a folder.
string[] pdfFiles = Directory.GetFiles(EnvSettingsTools.FilePath.ToString(), "*.pdf")
.Select(path => Path.GetFileNameWithoutExtension(path))
.ToArray();
How can i use this code to get the files by filter by date. The file format will be
LondoPage 20160301.pdf
I need to filter the files with the date in the end of filename. i.e, if i pass date '20160301' the mentioned file should select.
Try
var date = "20160301";
string[] pdfFiles = Directory.GetFiles(EnvSettingsTools.FilePath.ToString(), "*.pdf")
.Select(path => Path.GetFileNameWithoutExtension(path))
.Where(f => f.EndsWith(date))
.ToArray();
This will get files whose name ends with date you pass for filter:
var date = "20160301";
string[] pdfFiles = Directory.GetFiles(EnvSettingsTools.FilePath.ToString(), "*.pdf")
.Select(Path.GetFileNameWithoutExtension)
.Where(f => f.EndsWith(date))
.ToArray();
I did not quite understand your desired outcome but I will do an educated guess that you need to be able to order or filter the folder content. That can be achieved in more than one way. I will propose a solution to your problem
if (!Directory.Exists(pathToFiles)) return;
DirectoryInfo di = new DirectoryInfo(pathToFiles);
FileSystemInfo[] files = di.GetFileSystemInfos();
var orderedFiles = files.OrderBy(f => f.CreationTime);
var filteredFileByDate = orderedFiles.Where(f => f.FullName.ToLowerInvariant().Split('/').Last().Contains("filterText"));
With the ordered files you will receive all files ordered by a particular property, in this case I have chosen the creation date.
With the filtered file you will receive a collection of one or more files that mach your criteria. The more precise is your criteria the less results you get.
Hope that it helps ;)

GetDirectories - Find the directory that does not match the pattern

I have 140 directories that I'm trying to process. According to my tests there are 139 directories that match my file pattern (*abc.txt).
I'm trying to find the 1 directory to verify that in fact it does not have a *abc.txt in it.
How can I do this?
The following code gives me the 140 directories number:
var directoryCount = from subdirectory in Directory.GetDirectories(paramStartFilePath, "*", SearchOption.AllDirectories)
where Directory.GetDirectories(subdirectory).Length == 0
select subdirectory;
I'm gathering the files based off the pattern like this:
dirInfoFiles= new DirectoryInfo(startFilePath);
IEnumerable<FileInfo> listFiles = dirInfoFiles.EnumerateFiles("*abc.txt, System.IO.SearchOption.AllDirectories);
How can I find the the one directory that doesn't contain my .txt file?
There is always the running the tank through the village approach: just enumerate *.* and then exclude the patterns that don't match.
If you want all directories that does not contain at least one txt-file which name ends with "abc":
IEnumerable<DirectoryInfo> matchingDirs = dirInfoFiles.EnumerateDirectories("*.*", System.IO.SearchOption.AllDirectories)
.Where(d => !d.EnumerateFiles().Any(f => f.Extension.ToUpper() == ".TXT"
&& f.Name.EndsWith("abc", StringComparison.OrdinalIgnoreCase)));
or the same in other words, possibly more readable:
IEnumerable<DirectoryInfo> matchingDirs = dirInfoFiles
.EnumerateDirectories("*.*", System.IO.SearchOption.AllDirectories)
.Where(d => !d.EnumerateFiles("*abc.txt").Any());
Here is my take. It returns the first item (or null) that contains a file ending with the text you are looking for and is case insensitive. You could remove the lambdas to make it more readable.
var directory = Directory.GetDirectories((paramStartFilePath, "*", SearchOption.AllDirectories)
.FirstOrDefault(x => new DirectoryInfo(x).EnumerateFiles().Any(f => !f.Name.EndsWith("abc.txt",true,CultureInfo.CurrentCulture)));

Merge 2 foreach loops (Deleting files with specific extensions)

I got the following code :
foreach (string file in Directory.GetFiles(generationDir, "*.xaml")
{
File.Delete(file);
}
foreach (string file in Directory.GetFiles(generationDir, "*.cs")
{
File.Delete(file);
}
I'd like to merge these 2 foreach in a single loop ? Is that possible ?
I'm not comfortable with lambda expression so got a hard time here...
foreach (var file in
Directory.GetFiles(generationDir, "*.*")
.Where(item => item.EndsWith(".xaml") || item.EndsWith(".cs")))
{
File.Delete(file);
}
For those who like ForEach() "sequence operator fake" :)
(Please be aware of “foreach” vs “ForEach” before usign it)
Directory.GetFiles(generationDir, "*.*")
.Where(item => item.EndsWith(".xaml") || item.EndsWith(".cs"))
.ToList()
.ForEach(item => File.Delete(item))
If you are usign .NET Framework v4 you can use more efficient Directory.EnumerateFiles() method:
The EnumerateFiles and GetFiles methods differ as follows: When you
use EnumerateFiles, you can start enumerating the collection of names
before the whole collection is returned; when you use GetFiles, you
must wait for the whole array of names to be returned before you can
access the array. Therefore, when you are working with many files and
directories, EnumerateFiles can be more efficient.
The returned collection is not cached; each call to the GetEnumerator
on the collection will start a new enumeration.
You can just union the two sets
var items = Directory.GetFiles(generationDir, "*.xaml").Where(item => item.EndsWith(".xaml"))
.Union(Directory.GetFiles(generationDir, "*.cs").Where(item => item.EndswWith(".cs"))
Then foreach through them.
By the way, the where clause on each of the collections seems to be redundant to me, since GetFiles uses the mask you provided, so all of the files should end in .xaml or .cs.
How about with LINQ:
var files = from extension in new[] { "xaml", "cs" }
from fileName in Directory.GetFiles(generationDir, "*." + extension)
select fileName;
foreach(var file in files)
File.Delete(file);
Or in method syntax:
var files = new[] { "xaml", "cs" }
.SelectMany(extension => Directory.GetFiles(generationDir, "*." + extension))
foreach(var file in files)
File.Delete(file);
Remove the filter argument from the GetFiles method call and use and or in your where clause:
var files = Directory.GetFiles(generationDir).Where(item => item.EndsWith(".cs") || item.EndsWith(".xaml"));
foreach (var file in files)
{
File.Delete(file);
}
var filenames = (new[] { "*.cs", "*.xaml" }).SelectMany(
ext => Directory.GetFiles(generationDir, ext));
foreach(var filename in filenames)
File.Delete(filename);
I also removed the redundant Where statements since you were double filtering on the same criteria as you passed in to Directory.GetFiles.
try like this using this operator ||
foreach (string file in Directory.GetFiles(generationDir, "*.*")
.Where(item => item.EndsWith(".xaml") || item.EndsWith(".cs"))
{
File.Delete(file);
}

Using the linq search option in enumerate files

Quick one here. I am trying to EnumerateFiles in a C# application and I want to find all the files in a directory that do not match a given pattern. So I would have something like this:
var files = Directory.EnumerateFiles("MY_DIR_PATH", "NOT_MY_FILE_NAME");
Can someone help me out with the not part?
I don't think you can use that overload of EnumerateFiles for this, but you can use linq:
Directory.EnumerateFiles("MY_DIR_PATH").Where(s => s != "NOT_MY_FILE_NAME");
or in query syntax:
var files = from f in Directory.EnumerateFiles("MY_DIR_PATH")
where f != "NOT_MY_FILE_NAME"
select f;
You can do something like that:
var files = Directory.EnumerateFiles("MY_DIR_PATH")
.Where(fileName => fileName != "MY_FILE_NAME");
How about
var files = Directory.GetFiles("MY_DIR_PATH")
.Where(f => !f.Contains("NOT_MY_FILE_NAME"));

Categories

Resources