Reputation: 859
I have a function that cycles through a directory and, for each folder within that directory, returns the most recent file. The problem is that the folders contain files of different formats, such as .xlsx
and .csv
. The file extensions may change per request, so I need to pass them as a parameter to the function, instead of hard-coding the values. How can I pass a list of file extensions as a parameter and select the file according to its extension? Here's what I'm trying to do:
var extensions = new string[] { ".xlsx", ".csv" };
var filename = FileSystemService.GetRecentFile(path, extensions.ToList<string>);
Upvotes: 1
Views: 681
Reputation: 57593
If you need the most recent file having one of the extensions required, then this could be a solution:
public FileInfo GetRecent(string path, params string[] extensions)
{
var list = new List<FileInfo>();
// Getting all files having required extensions
// Note that extension is case insensitive with this code
foreach (var ext in extensions)
list.AddRange(
new DirectoryInfo(path)
.EnumerateFiles("*" + ext, SearchOption.AllDirectories)
.Where(p =>
p.Extension.Equals(ext,StringComparison.CurrentCultureIgnoreCase))
.ToArray());
return list.Any()
// If list has somm file then return the newest one
? list.OrderByDescending(i => i.LastWriteTime)
.FirstOrDefault()
// else return what you please, it could be null
: null;
}
If you need the most recent file for each extension, then this could be a solution:
public Dictionary<string, FileInfo> GetRecents(string path, params string[] extensions)
{
var ret = new Dictionary<string, FileInfo>();
// Getting all files having required extensions
// Note that extension is case insensitive with this code
foreach (var ext in extensions)
{
var files = new DirectoryInfo(path)
.EnumerateFiles("*" + ext, SearchOption.AllDirectories)
.Where(p =>
p.Extension.Equals(ext, StringComparison.CurrentCultureIgnoreCase))
.ToArray();
ret.Add(ext, files.Any()
? files.OrderByDescending(i => i.LastWriteTime).FirstOrDefault()
: null);
}
return ret;
}
Upvotes: 2
Reputation: 32288
You could first enumerate the Sub-Directories in the provided path, using Directory.EnumerateDirectories. This enumeration excludes the root, so we can add it back to the Enumerable, if required, using the Prepend()1 or Append()1 methods.
Then iterate the collection of extensions, call DirectoryInfo.EnumerateFiles to get Date/Time information about the files in each Directory and filter using the FileInfo.LastWriteTime
value and finally order by the most recent and yield return
the first result.
I've used a public methods that calls a private worker method, so the public method can be used to provide some more filters or it could be more easily overloaded. Here it's used to provide an option to return the most recent file of all.
It can be called as:
string[] extensions = { ".png", ".jpg", "*.txt" };
var mostRecentFiles = GetMostRecentFilesByExtension(@"[RootPath]", extensions, false);
Specify false
to get all the files by type and directory, or true
to get the most recent file among all files that matched the criteria.
public IEnumerable<FileInfo> GetMostRecentFilesByExtension(string path, IEnumerable<string> extensions, bool returnSingle)
{
var mostRecent = MostRecentFileByExtension(path, extensions).Where(fi => fi != null);
if (returnSingle) {
return mostRecent.OrderByDescending(fi => fi.LastWriteTime).Take(1);
}
else {
return mostRecent;
}
}
private IEnumerable<FileInfo> MostRecentFileByExtension(string path, IEnumerable<string> exts)
{
foreach (string dir in Directory.EnumerateDirectories(path, "*", SearchOption.AllDirectories).Prepend(path))
foreach (string ext in exts) {
yield return new DirectoryInfo(dir)
.EnumerateFiles($"*{ext}")
.Where(fi => fi.Extension.Equals(ext, StringComparison.InvariantCultureIgnoreCase))
.OrderByDescending(fi => fi.LastWriteTime).FirstOrDefault();
}
}
(1) Both
Prepend()
andAppend()
require .Net Framework 4.7.1. Core/Standard Frameworks all have them.
Upvotes: 2