2

如何检索文件夹任何后代的最新写入时间?

我需要一个方法来返回在指定日期时间之后修改的所有文件的路径。我想我可以通过确保目录LastWriteTime在指定范围内来节省大量昂贵的磁盘读取,然后再遍历其文件和子目录。

这样做的原因是,当目录顶层中的文件发生更改时,文件夹的最后写入时间也会更新。但是,最后一次写入时间不会比文件的直接父级更远。换句话说,如果孙文件被改变,它的属性被更新,它的父亲文件夹也是如此,但不是祖父文件夹。

是否有另一个高级指标可以用来完成此操作,或者我是否必须求助于递归遍历每个文件夹,而不管上次更改时间如何?

这是目前的方法:

private void AddAllFilesOfAllSubdirsWithFilterToList(string dirPath, ref List<FileInfo> filesList, DateTime minDate)
{
    // Return files in this directory level
    foreach (string filePath in Directory.GetFiles(dirPath, "*.*", SearchOption.TopDirectoryOnly))
    {
        FileInfo fileInfo = new FileInfo(filePath);
        if (fileInfo.LastWriteTimeUtc > minDate)
        {
            filesList.Add(fileInfo);
        }
    }

    // Return recursive searches through sudirs
    foreach (string subDirPath in Directory.GetDirectories(dirPath))
    {
        DirectoryInfo dirInfo = new DirectoryInfo(subDirPath);
        if (dirInfo.LastWriteTimeUtc > minDate)
        {
            GetAllFilesOfAllSubdirsWithFilter(subDirPath, ref filesList);
        }
    }
}
4

3 回答 3

2

感谢你的帮助!

摘要:因此,由于DirectoryInfo对象上没有显示文件树中任何后代的最后写入时间的属性(仅适用于子文件),因此让 CLR 返回所有后代文件的集合似乎是一个简单的修复方法

Directory.GetFiles(dirPath, "*.*", SearchOption.AllDirectories);

但是,在我的情况下,这有一些性能弱点:

  1. 这个过程是从后端 Web 处理程序运行的,因此性能很重要,因为浏览器正在等待写入目录结果
  2. 所有文件都由 返回GetFiles,让您在之后过滤它们。就我而言,这是一个庞大的集合,我只能从中收集到少数最近更改的文件
  3. 我之前没有提到这一点,但我也有一些我不想搜索的路径集合,我在我的实际代码中传递了这些路径——在迭代子文件夹之前检查路径为我提供了性能改进

这是我现在拥有的:

private void AddAllFilesOfAllSubdirsWithFilterToList(ref List<FileInfo> filesList, string dirPath, DateTime startDateUtc, DateTime? optionalEndDateUtc = null, List<string> blockedDirs = null)
{
    // Input validation
    if (String.IsNullOrEmpty(dirPath))
    {
        throw new ArgumentException("Cannot search and empty path");
    }

    DirectoryInfo currentDir = new DirectoryInfo(dirPath);
    if (!currentDir.Exists)
    {
        throw new DirectoryNotFoundException(dirPath + " does not exist");
    }
    if (filesList == null)
    {
        filesList = new List<FileInfo>();
    }

    // Set endDate; add an hour to be safe
    DateTime endDateUtc = optionalEndDateUtc ?? DateTime.UtcNow.AddHours(1);

    // The current folder's LastWriteTime DOES update every time a child FILE is written to,
    // so if the current folder does not pass the date filter, we already know that no files within will pass, either
    if (currentDir.LastWriteTimeUtc >= startDateUtc && currentDir.LastWriteTimeUtc <= endDateUtc)
    {
        foreach (string filePath in Directory.GetFiles(dirPath, "*.*", SearchOption.TopDirectoryOnly))
        {
            FileInfo fileInfo = new FileInfo(filePath);
            if (fileInfo.LastWriteTimeUtc > _sinceDate)
            {
                filesList.Add(fileInfo);
            }
        }
    }

    // Unfortunately, the current folder's LastWriteTime does NOT update every time a child FOLDER is written to,
    // so we have to search ALL subdirectories regardless of the current folder's LastWriteTime
    foreach (string subDirPath in Directory.GetDirectories(dirPath))
    {
        if (blockedDirs == null || !blockedDirs.Any(p => subDirPath.ToLower().Contains(p)))
        {
            AddAllFilesOfAllSubdirsWithFilterToList(ref filesList, subDirPath, startDateUtc, optionalEndDateUtc, blockedDirs);
        }
    }
}
于 2013-04-19T15:54:19.320 回答
2

很抱歉,但我认为您必须浏览所有子目录。

只需从上面的代码中更改您的 SearchOption 以通过子目录递归...

private void AddAllFilesOfAllSubdirsWithFilterToList(string dirPath, ref List<FileInfo> filesList, DateTime minDate)
{
    // I'm assuming you want to clear this here... I would generally return it 
    //   instead of passing it as ref
    filesList.Clear();

    // Return all files in directory tree
    foreach (string filePath in Directory.GetFiles(dirPath, "*.*", SearchOption.AllDirectories))
    {
        FileInfo fileInfo = new FileInfo(filePath);
        if (fileInfo.LastWriteTimeUtc > minDate)
        {
            filesList.Add(fileInfo);
        }
    }
}
于 2013-04-18T18:23:02.493 回答
1

不必通过目录树递归。CLR 非常乐意为您做这件事。

public FileInfo[] RecentlyWrittenFilesWithin( string path , string searchPattern , DateTime dateFrom , DateTime dateThru )
{
  if ( string.IsNullOrWhiteSpace( path ) ) {  throw new ArgumentException("invalid path" , "path" );}
  DirectoryInfo root = new DirectoryInfo(path) ;
  if ( !root.Exists ) {  throw new ArgumentException( "non-existent directory" , "path" ) ; }
  bool isDirectory = FileAttributes.Directory == ( FileAttributes.Directory & root.Attributes ) ;
  if ( isDirectory ) {  throw new ArgumentException("not a directory","path");}

  FileInfo[] files = root.EnumerateFiles( searchPattern , SearchOption.AllDirectories )
                         .Where( fi => fi.LastWriteTime >= dateFrom && fi.LastWriteTime <= dateThru )
                         .ToArray()
                         ;
  return files ;
}

根据这里的上下文(例如,如果你的程序是某种服务),你可以FileSystemWatcher在你的根目录上建立一个并监控发生的变化。

于 2013-04-18T18:23:55.567 回答