How to Filter Directory.Enumeratefiles with Multiple Criteria

How to filter Directory.EnumerateFiles with multiple criteria?

I created some helper methods to solve this which I blogged about earlier this year.

One version takes a regex pattern \.mp3|\.mp4, and the other a string list and runs in parallel.

public static class MyDirectory
{ // Regex version
public static IEnumerable<string> GetFiles(string path,
string searchPatternExpression = "",
SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
Regex reSearchPattern = new Regex(searchPatternExpression, RegexOptions.IgnoreCase);
return Directory.EnumerateFiles(path, "*", searchOption)
.Where(file =>
reSearchPattern.IsMatch(Path.GetExtension(file)));
}

// Takes same patterns, and executes in parallel
public static IEnumerable<string> GetFiles(string path,
string[] searchPatterns,
SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
return searchPatterns.AsParallel()
.SelectMany(searchPattern =>
Directory.EnumerateFiles(path, searchPattern, searchOption));
}
}

Directory.EnumerateFiles with special filters

Check extension length and last letter.

var files = Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories)
.Where(s =>
{
string ext = Path.GetExtension(s);
return ext.Length == 4 && ext.EndsWith("b")
|| s.EndsWith(".in")
|| s.EndsWith(".txt");
});

Can you call Directory.GetFiles() with multiple filters?

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.

Exclude files from Directory.EnumerateFiles based on multiple criteria

Here's one way that uses FileInfo objects instead of strings. This eliminates all those Path calls, but should be easy to change if desired.

Dim ext() As String = {".jpg", ".gif", ".bmp", ".tif", ".png", ".tiff", ".jpeg"}
Dim exclusion() As String = {"thumb", "nothing", "empty"}
Dim fileArray = From chkFile As FileInfo In New DirectoryInfo(fpath).EnumerateFiles("*.*", SearchOption.TopDirectoryOnly)
Where ext.Contains(chkFile.Extension.ToLower(System.Globalization.CultureInfo.InvariantCulture)) _
And Not exclusion.Any(Function(x) chkFile.Name.ToLower(System.Globalization.CultureInfo.InvariantCulture).Contains(x))
Select chkFile

Multiple file-extensions searchPattern for System.IO.Directory.GetFiles

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

how to read all files in particular folder and filter more than one type?

You can concatenate two results like this

foreach (string file in Directory.EnumerateFiles(folderPath, "*.txt").Concat(Directory.EnumerateFiles(folderPath, "*.bmp")))
{
// (code here)
}

Or make it a function like so

    IEnumerable<string> EnumerateFiles(string folderPath, params string[] patterns)
{
return patterns.SelectMany(pattern => Directory.EnumerateFiles(folderPath, pattern));
}

void Later()
{
foreach (var file in EnumerateFiles(".", "*.config", "*.exe"))
{
// (code here)
}
}

Directory.EnumerateFiles method: How to enumerate files in specified subdirectories?

Please consider some implementation like this one:

public static class Program
{
public static void Main()
{
var directoryPaths = new List<string>
{
@"C:\root\path_1",
@"C:\root\path_2",
@"C:\root\path_3"
// …
};
var searchPatterns = new List<string>
{
"*.jpg",
"*.gif"
};

var filePaths = directoryPaths
.SelectMany(directoryPath =>
EnumerateFiles(directoryPath, searchPatterns, SearchOption.AllDirectories))
.ToList()
.AsReadOnly();

// …
}

private static IEnumerable<string> EnumerateFiles(
string path,
IEnumerable<string> searchPatterns,
SearchOption searchOption)
{
var filePaths = searchPatterns.SelectMany(
searchPattern => Directory.EnumerateFiles(path, searchPattern, searchOption));
return filePaths;
}
}

Directory.EnumerateFiles with Take and Where

You need to reorder your statement to put the Where before the Take:

For Each _file As String In Directory.EnumerateFiles(Quellpfad, "*.rdy").Where(Function(item) item.Replace(Quellpfad, "").Length <= 11).Take(500)

The Where returns all files matching your condition FIRST, and THEN limits those down to 500.



Related Topics



Leave a reply



Submit