如何在不使用循环的情况下使用.NET在目录中查找最新文件?


142

我需要在目录中找到最新修改的文​​件。

我知道我可以遍历文件夹中的每个文件并进行比较File.GetLastWriteTime,但是有没有更好的方法可以做到这一点而无需循环?


18
没有没有更好的方法可以避免循环。即使使用LINQ,也只会将循环隐藏到一些更深层次的功能中,而您无法直接看到它。
奥利弗

1
如果要在整个文件系统上查找最新修改的文​​件,则NTFS更改日志将很有用。但是,从C#中很难使用。
Ben Voigt 2014年

Answers:


318

这样的事情怎么样...

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

84
就个人而言,我发现非加糖版本更容易阅读:directory.GetFiles().OrderByDescending(f => f.LastWriteTime).First()
约恩休乌-罗德

6
是的,我也大部分时间都同意-但是在举个例子时,查询语法使它更明显地表明它是linq查询。我将使用两个选项来更新示例以进行澄清。
Scott Ivey

3
谢谢!现在,我只需要说服老板加快从.net 2.0升级的过程,以便我可以使用Linq :)
Chris Klepeis 09年

3
你可以用2.0 SP1使用LINQ有一些额外的工作-刚刚从3.5引用System.Core.dll文件,并将其设置为“复制本地”
斯科特艾维

8
这不应该FirstOrDefault()代替First()吗?InvalidOperationException如果目录为空,则后者将导致。
Tobias J

20

如果要递归搜索,可以使用下面这段漂亮的代码:

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

只需按以下方式调用它:

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

就是这样。返回一个FileInfo实例,或者null目录为空。


12
或者,您可以使用递归搜索选项。
ricksmt

17

扩展上面的第一个,如果要搜索某个模式,可以使用以下代码:

string pattern = "*.txt";
var dirInfo = new DirectoryInfo(directory);
var file = (from f in dirInfo.GetFiles(pattern) orderby f.LastWriteTime descending select f).First();

我需要那个 谢谢。
ashilon

10

非LINQ版本:

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

1
抱歉,没有看到您不想循环的事实。无论如何...也许它将帮助某人搜索类似的东西
TimothyP 2009年

3
此代码无法编译。-lastUpdatedFile不应为数组。-lastUpdate的初始值无效(0001/0/0)。
拉尔斯·布雷肯

4

简短

new DirectoryInfo(path).GetFiles().OrderByDescending(o => o.LastWriteTime).FirstOrDefault();

3

有点晚了,但是...

由于list<FileInfo> lastUpdateFile = null; 及之后的原因,您的代码将无法工作,lastUpdatedFile.Add(file);因此将引发NullReference异常。工作版本应为:

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

谢谢


2

您可以使用FileSystemWatcher对新文件活动做出反应。


1
它不起作用,因为可以在文件的应用程序不运行时对其进行修改。
Francis B.

1
他没有提供详细信息...我们怎么知道它不是持久性应用程序?
Scott Marlowe

1
我们没有,但是Scott有一个更好的解决方案,在两种情况下都有效。
巴达罗

另外,请注意,FSW不适用于大多数网络共享文件夹。
bkqc

2

如果您正在使用Directory.EnumerateFiles并且想读取最新修改的文​​件,则可以采用另一种方法。

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

}

1

这是一个从每个子目录获取最新文件的版本

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

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

0

我这样做是一堆我的应用程序,我使用如下语句:

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

从这里,您将在“ inputDirectory”变量的目录中拥有最近保存/添加/更新的文件的文件名。现在,您可以访问它并使用它来做您想做的。

希望有帮助。


除此之外,如果您的目标是找回文件路径,并且您正在使用FirstOrDefault,因为可能没有结果,则可以对FullName属性使用空条件运算符。这将使您返回“ null”作为路径,而无需在调用FullName之前从FirstOrDefault中保存FileInfo。字符串路径=新的DirectoryInfo(path).GetFiles()。OrderByDescending(o => o.LastWriteTime).FirstOrDefault()?. FullName;
StalePhish
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.