C#: Get the 5 newest (last modified) files from a directory - c#

Is there a way I can store the file location of the 5 last modified files from a directory using Array?
I am currently using the following codes below to get the last file:
DateTime lastHigh = new DateTime(1900,1,1);
string highDir;
foreach (string subdir in Directory.GetDirectories(path)){
DirectoryInfo fi1 = new DirectoryInfo(subdir);
DateTime created = fi1.LastWriteTime;
if (created > lastHigh){
highDir = subdir;
lastHigh = created;
}
}
I'll be using Array to send multiple files to an email address as attachment.
UPDATE
I am currently using the codes below to get the last modified files after 1 minute:
string myDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),
"Test Folder");
var directory = new DirectoryInfo(myDirectory);
DateTime from_date = DateTime.Now.AddMinutes(-1);
DateTime to_date = DateTime.Now;
var files = directory.GetFiles().Where(file => file.LastWriteTime >= from_date && file.LastWriteTime <= to_date);
I want to store to list of file names coming from files

Here's a general way to do this with LINQ:
Directory.GetFiles(path)
.Select(x => new FileInfo(x))
.OrderByDescending(x => x.LastWriteTime)
.Take(5)
.ToArray()
I suspect this isn't quite what you want, since your code examples seem to be working at different tasks, but in the general case, this would do what the title of your question requests.

It sounds like you want a string array of the full filepaths of all the files in a directory.
Given you already have your FileInfo enumerable, you can do this:
var filenames = files.Select(f => f.FullName).ToArray();
If you wanted just the filenames, replace FullName with Name.

While the answer Paul Phillips provided worked. It's worth to keep in mind that the
FileInfo.LastWriteTime & FileInfo.LastAccessTime do not always work. It depends on how the OS is configured or could be a caching issue.
.NET FileInfo.LastWriteTime & FileInfo.LastAccessTime are wrong
File.GetLastWriteTime seems to be returning 'out of date' value

Related

How to fetch a particular filename pattern from directory

I'm trying to fetch a particular filename from a directory. The code I've tried is as below
DirectoryInfo dirInfo = new DirectoryInfo(directoryPath);
FileInfo recentlyModLogFile = (from files in dirInfo.GetFiles("^Monarch_[0-9]{2}$") orderby files.LastWriteTime descending select files).First();
//Output : Error
List of file names (Input)
Monarch_05bridge //Date modified 16-12-2021 20:41
Monarch_04bridge //Date modified 16-12-2021 06:49
Monarch_04 //Date modified 16-12-2021 05:39
Monarch_02 //Date modified 16-12-2021 05:49
Monarch_02bridge //Date modified 14-12-2021 19:34
Monarch_01 //Date modified 14-12-2021 09:08
Code should look for files whose filename starts with Monarch_ followed by 2 numeric digits and then filter out the recently modified file
So the output should be Monarch_02
I also tried doing
DirectoryInfo dirInfo = new DirectoryInfo(directoryPath);
FileInfo recentlyModLogFile = (from files in dirInfo.GetFiles(Monarch_ + "*") orderby files.LastWriteTime descending select files).First();
//OUtput : Monarch_05bridge
Can someone help me to resolve this issue.
string youngestFile = Directory.GetFiles(directoryPath)
.Where(o => Regexp.Contains(Path.GetFileNameWithoutExtension(o), "Monarch_\\d\\d"))
.OrderByDescending(o => File.GetLastWriteTime(o))
.FirstOrDefault();
This is a quick copy-and-paste from my project files. The Regexp.Contains() is one of the simple methods I wrote to do regexp comparisons.
Notice the Regular Expression I used allow Monarch_02, Monarch_02Bridge and abcMonarch_09 all to be possible result. You can use "^Monarch_\\d\\d$", if you want a strict rule.
Refer to Regular Expressions for details.
private static Match GetFirstMatch(string text, string pattern)
{
Match match = Regex.Match(text, pattern, RegexOptions.None);
return match;
}
public static Boolean Contains(string text, string pattern)
{
return GetFirstMatch(text, pattern).Value != String.Empty;
}
Basically, use Directory.GetFiles(path) to get all the files, then use LINQ to apply conditions, order-bys and fetch the first result.
The Path, Directory and File classes can help a lot when you are working around file system.

C# get Files from directory with specific CreationTime

i am writing a short code to move files from one directory to another. My code is simple, working fine and looks like this:
public void copy()
{
string sourcePath = #"/Users/philip/Desktop/start";
string destinationPath = #"/Users/philip/Desktop/Ziel";
string[] files = Directory.GetFiles(sourcePath)
foreach (string s in files)
{
string fileName = System.IO.Path.GetFileName(s);
string destFile = System.IO.Path.Combine(destinationPath, fileName);
System.IO.File.Copy(s, destFile, true);
}
}
The Programm gets all files from the sourcepath and combines the targetpath in the foreach loop vor every file, containing of target path and filename. Then it moves it. Everything works fine.
My aim is now, not to store all files from my directory into the string array. I only want to get the files that have CreationTime after 01.07.2021. Is there an easy and quick way to do it?
I already used this to get the files, but it specifies a singular date and not all files after a specific date:
var files = Directory.GetFiles(sourcePath).Where(x => new FileInfo(x).CreationTime.Date == DateTime.Today.Date);
I would be glad if you could help me out.
Best regards,
Liam
If you want to avoid having to check the creation date on every single FileInfo you can order your files. Like so:
var directory = new DirectoryInfo(sourcePath);
var fileInfos = directory.GetFiles().OrderByDescending(fileInfo => fileInfo.CreationDate);
var result = new List<FileInfo>();
foreach (var fileInfo in fileInfos)
{
if (fileInfo.CreationDate >= DateTime.Today)
result.Add(fileInfo);
else
break; // We can break early, because we ordered our dates descending
// meaning every date after this one is smaller
}
This has upsides and downsides, ordering a huge collection of files could take longer than "just" simply iterating over all and comparing the dates, but you'll need to benchmark it on your own
You could use FileInfo
FileInfo fileInfo = new(s);
if (fileInfo.CreationTime >= DateTime.Parse("01/07/2021"))
{
...
}

Remove older file(s) from list based on create date

I have a set of folders containing log files. Each folder is named as the date the log files were created. I am getting the content of these folders within X days of today and storing the resulting FileInfo in a list. So it is possible to have file info with same file name X times, or less.
I need to keep only the latest files based on create date. So, if the list contains multiple entries where fi.FileName is the same, I need to keep the latest, based on fi.CreateDate and ditch the other instance(s).
I tried something like this but am messing up somewhere:
files = files.GroupBy(i => new {i.FileName, i.CreateDate}).Select(i => i.Last()).ToList();
You must change your sort code as follows:
files = files.OrderBy(f=>f.CreateDate).GroupBy(i => i.FileName).Select(i => i.Last()).ToList();
This one also will give the same result:
files =files.GroupBy(i => i.FileName).Select(i => i.OrderByDescending(f=>f.CreateDate).First()).ToList();
You can use such a method to get files to purge:
using System.IO;
using System.Linq;
using System.Collections.Generic;
static public IEnumerable<FileInfo> GetTraceFiles(bool sortByDateOnly = true)
{
string folder = "MyFullPath"; // Can be from some instance
string prefix = "MyTraceFile-"; // global vars
string extension = ".log"; // and config
var list = Directory.GetFiles(folder, prefix + "*" + extension)
.Where(f => !IsFileLocked(f))
.Select(f => new FileInfo(f))
.OrderBy(fi => fi.CreationTime);
return sortByDateOnly ? list : list.ThenBy(fi => fi.FullName);
}
And this clear method:
static public void ClearTraces(int retain = 0)
{
var list = GetTraceFiles();
if ( retain > 0 ) list = list.Take(list.Count() - retain + 1);
foreach ( var fileInfo in list )
try
{
File.Delete(fileInfo.FullName);
}
catch
{
}
}
Here it retains retain last files but you can adapt to add a Where clause to use a date before which to erase:
.Where(fi => fi.CreationTime < ...);
Also instead of using the file system creation date and time, it is possible to use the file pattern in case for example MyTrace-YYYY-MM-DD#HH-MM-SS...
IsFileLocked comes from:
Is there a way to check if a file is in use?

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

How do I store only the folder names as an array and not the while path (C#)

So I know how to store the full path but not just the end folder names, for example I've already got an array but is there any method to remove certain characters from all arrays or just get folder names from a path?
Edit: string[] allFolders = Directory.GetDirectories(directory);
That's what I use to get all folder names but that gets me the whole path
Edit:They need to be stored in an Array
Edit: sorry , I need an array with values such as "mpbeach","blabla","keyboard" and not E:\Zmod\idk\DLC List Generator\DLC List Generator by Frazzlee\ , so basically not the full path
This works.
string[] allFolders = Directory.EnumerateDirectories(directory)
.Select(d => new DirectoryInfo(d).Name).ToArray();
This also works. Difference is we are using List<string> instead of string[]
List<string> allFolders = Directory.EnumerateDirectories(directory)
.Select(d => new DirectoryInfo(d).Name).ToList();
Example 1: Uses string[] allFolders
Test Folder
In VS IDE, in Debug Mode
Example 2: Uses List<string> allFolders
Test Folder
In VS IDE, in Debug Mode
Example 2: Uses string[] allFolders
No need for string operations... Just use DirectoryInfo class
var allFolders = new DirectoryInfo(directory).GetDirectories()
.Select(x => x.Name)
.ToArray();
NOTE I'm taking your question to mean how to extract the last folder name from a file URL. Others are reading this as how to extract the names of folders in a directory. If I'm wrong, it's because I'm misinterpreting your question.
Split by backslash to get folders. The next-to-last value is the last folder:
string folder = #"c:\mydrive\testfolder\hello.txt";
string[] parts = folder.Split('\\');
string lastFolder = parts[parts.Length - 1];
//Yields "testfolder";
Moving that forward to what you want:
private string[] foldersOnly(){
List<string> folders = new List<string>();
string[] allFolders = Directory.GetDirectories(directory);
foreach(string folder in allfolders){
string[] parts = folder.Split('\\');
folders.Add(parts[parts.Length-1]);
}
}
return folders.ToArray();

Categories