【问题标题】:Remove older file(s) from list based on create date根据创建日期从列表中删除旧文件
【发布时间】:2021-08-21 18:28:46
【问题描述】:

我有一组包含日志文件的文件夹。每个文件夹都以创建日志文件的日期命名。我将在今天的 X 天内获取这些文件夹的内容,并将生成的 FileInfo 存储在一个列表中。因此,有可能拥有相同文件名 X 次或更少的文件信息。

我只需要根据创建日期保留最新的文件。因此,如果列表包含多个 fi.FileName 相同的条目,我需要根据 fi.CreateDate 保留最新的并放弃其他实例。

我尝试过这样的事情,但在某个地方搞砸了:

files = files.GroupBy(i => new {i.FileName, i.CreateDate}).Select(i => i.Last()).ToList();

【问题讨论】:

  • 你能分享日志文件的示例文件名吗?
  • _
  • 请注意,文件系统日期完全不可靠,可能并不总是您所期望的。
  • @Alejandro 对!我将一组文件按日期复制到多个目录中,从生产站点到我的开发箱进行测试。当我尝试按 create_date 或 last_write_date 排序时,它们都有我复制文件的日期。所以又卡住了!

标签: c# list linq


【解决方案1】:

您必须按如下方式更改排序代码:

  files = files.OrderBy(f=>f.CreateDate).GroupBy(i => i.FileName).Select(i => i.Last()).ToList();

这也将给出相同的结果:

 files =files.GroupBy(i => i.FileName).Select(i => i.OrderByDescending(f=>f.CreateDate).First()).ToList();

【讨论】:

  • 这很好用。但是,我不得不将 select() 更改为 Select(i => i.OrderByDescending(f => f.DirectoryName) 因为我的文件位于以创建日期命名的目录中,并且 f.CreateDate 和 f.LastWriteDate 被证明是不可靠的。特别是如果您将它们从一个位置复制到另一个位置并处理复制的文件。
【解决方案2】:

您可以使用这样的方法来获取要清除的文件:

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

还有这个清晰的方法:

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

这里它保留retain最后一个文件,但您可以适应添加Where子句以使用删除之前的日期:

.Where(fi => fi.CreationTime < ...);

除了使用文件系统创建日期和时间,还可以使用文件模式,例如MyTrace-YYYY-MM-DD@HH-MM-SS...

IsFileLocked 来自:

Is there a way to check if a file is in use?

【讨论】:

  • 这有效,除了我必须将 f => new FileInfo(f) 更改为 f => new FileInfo(f.Name) 并且 IsFileLocked 似乎不是 FileInfo 的一部分,除非它是一些方法我必须自己创建。
  • @Alejandro 提到使用创建日期似乎不可靠。我从生产服务器复制了几个文件夹(称为 2021-06-03 和 2021-06-04)中的文件,这些文件夹的创建日期与相应文件夹名称相同。现在它们都将创建日期和最后写入日期显示为 06/04。看来得另找办法测试了。文件名本身没有嵌入名称中的日期,而是它们所在的文件夹是它们创建的数据。
  • @NoBullMan 确实,除非使用像 Total Commander 这样可以保存日期的文件管理器。这就是为什么我提到文件名模式作为一种更独立使用的可能性。
  • 只是在这里大声思考:也许我需要使用具有一个属性为 FileInfo 和另一个文件夹名称的对象列表而不是 FileInfo 列表,并使用文件夹名称属性进行排序。尽管 FileInfo 中确实有文件夹名称。大脑过热!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多