C# - 获取文件夹后代的LastWriteTime

时间:2013-04-18 17:54:23

标签: c# file-io directory

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

我需要一个方法来返回在指定的DateTime之后修改的所有文件的路径。我想通过确保目录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);
        }
    }
}

3 个答案:

答案 0 :(得分: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);
        }
    }
}

答案 1 :(得分:2)

感谢您的帮助!

摘要:因此,因为DirectoryInfo对象上没有显示文件树中任何后代的上次写入时间的属性(仅适用于子文件),所以让CLR返回所有后代文件的集合似乎很容易使用

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

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

  1. 此过程从后端Web处理程序运行,因此性能是一个大问题,因为浏览器正在等待目录结果写入
  2. 所有文件都由GetFiles返回,让您以后过滤它们。在我的情况下,这是一个巨大的集合,我可以从中收集最近几个已更改的文件
  3. 之前我没有提到这个,但是我也有一些我不想搜索的路径,我在实际代码中传入 - 在迭代子文件夹之前检查路径提供了性能改进对我来说
  4. 以下是我现在所拥有的:

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

答案 2 :(得分: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并监视发生的更改。