How to find the most recent file in a directory using .NET, and without looping?
Asked Answered
S

11

176

I need to find the most recently modified file in a directory.

I know I can loop through every file in a folder and compare File.GetLastWriteTime, but is there a better way to do this without looping?.

Saguache answered 24/7, 2009 at 20:22 Comment(2)
No there is no better way which avoids looping. Even using LINQ just hides the looping into some deeper functionality where you can't see it directly.Bullough
If you wanted to find the most recently modified file(s) on the whole filesystem, then the NTFS Change Journal would be useful. Very very hard to use from C#, though.Harewood
O
382

how about something like this...

var directory = new DirectoryInfo("C:\\MyDirectory");
var myFile = (from f in directory.GetFiles()
             orderby f.LastWriteTime descending
             select f).First();

// or...
var myFile = directory.GetFiles()
             .OrderByDescending(f => f.LastWriteTime)
             .First();
Obliterate answered 24/7, 2009 at 20:25 Comment(13)
Personally, I find that the non-sugared version is easier to read: directory.GetFiles().OrderByDescending(f => f.LastWriteTime).First()Its
yeah, i agree most of the time too - but when giving examples the query syntax makes it a bit more obvious that it's a linq query. I'll update the example with both options to clarify.Obliterate
Thanks! Now I just need to convince my boss to expedite the process of upgrading us from .net 2.0 so I can use Linq :)Saguache
you can use linq with 2.0 SP1 with a little extra work - just reference the System.Core.dll file from 3.5, and set it to "copy local"Obliterate
Nice, must be a loop under there somewhere. :) I guess if you don't see it it's not there. +1Antung
There is still a loop right? I guess he is looking for a system call where you can specify a filter based on the date and the collection returned contains only the latest file. But again I do not think that looping make much difference here in terms of performance if the details about files are returned from NTFS.Lactation
What if the directory is in a server... (e.g. \\myserver\myfolder\files.csv)?Secretion
@SiKni8, it should work the same. You'd just need to escape your backslashes. DirectoryInfo(@"\\myserver\myfolder") or DirectoryInfo("\\\\myserver\\myfolder") should both work.Obliterate
Only the later one works :) Thank you for the response.Secretion
Careful using LastWriteTime, this value will return January 1st, 1600 if the file has never been modified. This will mess your sorting up.Avitzur
Shouldn't this use FirstOrDefault() instead of First()? The latter will cause an InvalidOperationException if the directory is empty.Miskolc
Is there any way to ignore temporary files? If I have one of the files open in the directory I am searching, I get the temporary file returned.Decaffeinate
SkinnyPete63 You can use a searchPattern on the GetFiles method eg."*.pdf" Or "Ab?D*.??F"Valona
A
37

Expanding on the first one above, if you want to search for a certain pattern you may use the following code:

using System.IO;
using System.Linq;
...
string pattern = "*.txt";
var dirInfo = new DirectoryInfo(directory);
var file = (from f in dirInfo.GetFiles(pattern) orderby f.LastWriteTime descending select f).First();
Arne answered 11/7, 2012 at 2:20 Comment(2)
I needed that. Thank you.Plat
For those who may forget: You have to include using System.Linq or else there will be an error.Rusty
G
21

If you want to search recursively, you can use this beautiful piece of code:

public static FileInfo GetNewestFile(DirectoryInfo directory) {
   return directory.GetFiles()
       .Union(directory.GetDirectories().Select(d => GetNewestFile(d)))
       .OrderByDescending(f => (f == null ? DateTime.MinValue : f.LastWriteTime))
       .FirstOrDefault();                        
}

Just call it the following way:

FileInfo newestFile = GetNewestFile(new DirectoryInfo(@"C:\directory\"));

and that's it. Returns a FileInfo instance or null if the directory is empty.

Graphophone answered 24/4, 2011 at 3:55 Comment(1)
Or you can use the recursive search option.Mantle
B
11

A non-LINQ version:

/// <summary>
/// Returns latest writen file from the specified directory.
/// If the directory does not exist or doesn't contain any file, DateTime.MinValue is returned.
/// </summary>
/// <param name="directoryInfo">Path of the directory that needs to be scanned</param>
/// <returns></returns>
private static DateTime GetLatestWriteTimeFromFileInDirectory(DirectoryInfo directoryInfo)
{
    if (directoryInfo == null || !directoryInfo.Exists)
        return DateTime.MinValue;

    FileInfo[] files = directoryInfo.GetFiles();
    DateTime lastWrite = DateTime.MinValue;

    foreach (FileInfo file in files)
    {
        if (file.LastWriteTime > lastWrite)
        {
            lastWrite = file.LastWriteTime;
        }
    }

    return lastWrite;
}

/// <summary>
/// Returns file's latest writen timestamp from the specified directory.
/// If the directory does not exist or doesn't contain any file, null is returned.
/// </summary>
/// <param name="directoryInfo">Path of the directory that needs to be scanned</param>
/// <returns></returns>
private static FileInfo GetLatestWritenFileFileInDirectory(DirectoryInfo directoryInfo)
{
    if (directoryInfo == null || !directoryInfo.Exists)
        return null;

    FileInfo[] files = directoryInfo.GetFiles();
    DateTime lastWrite = DateTime.MinValue;
    FileInfo lastWritenFile = null;

    foreach (FileInfo file in files)
    {
        if (file.LastWriteTime > lastWrite)
        {
            lastWrite = file.LastWriteTime;
            lastWritenFile = file;
        }
    }
    return lastWritenFile;
}
Billboard answered 23/11, 2009 at 7:51 Comment(2)
Sorry , didn't see the fact that you did not want to loop. Anyway... perhaps it will help someone searching something similarBillboard
This code does not compile. - lastUpdatedFile should not be an array. - The initial value for lastUpdate is invalid (0001/0/0).Scrivings
T
9

Short and simple:

new DirectoryInfo(path).GetFiles().OrderByDescending(o => o.LastWriteTime).FirstOrDefault();
Theatheaceous answered 13/8, 2017 at 1:46 Comment(0)
J
4

Another approach if you are using Directory.EnumerateFiles and want to read files in latest modified by first.

foreach (string file in Directory.EnumerateFiles(fileDirectory, fileType).OrderByDescending(f => new FileInfo(f).LastWriteTime))

}
Jutland answered 28/6, 2018 at 6:21 Comment(0)
R
3

You can react to new file activity with FileSystemWatcher.

Rubio answered 24/7, 2009 at 20:25 Comment(4)
It doesn't work because a file can be modified while his application is not running.Flamen
he didn't give that kind of detail... How do we know it isn't a persistant app?Rubio
We don't, but Scott has a better solution what works in both cases.Farnsworth
Also, note that FSW will not work with most network shared folders.Plaid
G
3

it's a bit late but...

your code will not work, because of list<FileInfo> lastUpdateFile = null; and later lastUpdatedFile.Add(file); so NullReference exception will be thrown. Working version should be:

private List<FileInfo> GetLastUpdatedFileInDirectory(DirectoryInfo directoryInfo)
{
    FileInfo[] files = directoryInfo.GetFiles();
    List<FileInfo> lastUpdatedFile = new List<FileInfo>();
    DateTime lastUpdate = DateTime.MinValue;
    foreach (FileInfo file in files)
    {
        if (file.LastAccessTime > lastUpdate)
        {
            lastUpdatedFile.Add(file);
            lastUpdate = file.LastAccessTime;
        }
    }

    return lastUpdatedFile;
}

Thanks

Grizzled answered 27/5, 2014 at 19:58 Comment(0)
R
2

Here's a version that gets the most recent file from each subdirectory

List<string> reports = new List<string>();    
DirectoryInfo directory = new DirectoryInfo(ReportsRoot);
directory.GetFiles("*.xlsx", SearchOption.AllDirectories).GroupBy(fl => fl.DirectoryName)
.ForEach(g => reports.Add(g.OrderByDescending(fi => fi.LastWriteTime).First().FullName));
Retreat answered 9/9, 2013 at 15:19 Comment(0)
C
0
private List<FileInfo> GetLastUpdatedFileInDirectory(DirectoryInfo directoryInfo)
{
    FileInfo[] files = directoryInfo.GetFiles();
    List<FileInfo> lastUpdatedFile = null;
    DateTime lastUpdate = new DateTime(1, 0, 0);
    foreach (FileInfo file in files)
    {
        if (file.LastAccessTime > lastUpdate)
        {
            lastUpdatedFile.Add(file);
            lastUpdate = file.LastAccessTime;
        }
    }

    return lastUpdatedFile;
}
Chucho answered 7/2, 2012 at 7:48 Comment(0)
E
0

I do this is a bunch of my apps and I use a statement like this:

  var inputDirectory = new DirectoryInfo("\\Directory_Path_here");
  var myFile = inputDirectory.GetFiles().OrderByDescending(f => f.LastWriteTime).First();

From here you will have the filename for the most recently saved/added/updated file in the Directory of the "inputDirectory" variable. Now you can access it and do what you want with it.

Hope that helps.

Electric answered 23/2, 2016 at 18:55 Comment(1)
To add on to this, if your goal is to get back the file path, and you're using FirstOrDefault because it's possible that there are no results, you can use the null-conditional operator on the FullName property. This will return you back "null" for your path without having to save off the FileInfo from FirstOrDefault before you call FullName. string path = new DirectoryInfo(path).GetFiles().OrderByDescending(o => o.LastWriteTime).FirstOrDefault()?.FullName;Bestrew

© 2022 - 2025 — McMap. All rights reserved.