在 C# 中检查文件的最后修改日期

Posted

技术标签:

【中文标题】在 C# 中检查文件的最后修改日期【英文标题】:Check last modified date of file in C# 【发布时间】:2011-03-22 13:54:20 【问题描述】:

我正在寻找一种方法来查看文件最后一次在 C# 中的修改时间。我拥有该文件的完全访问权限。

【问题讨论】:

How to get Modified date from file in c# 的可能重复项 以上链接中的问题是针对更具体的情况,但我同意 - 该问题中提到了此处接受的答案。 【参考方案1】:

System.IO.File.GetLastWriteTime 是您所需要的。

【讨论】:

甚至可能是System.IO.File.GetLastWriteTimeUtc 可悲的事实 - GetLastWriteTime 没有得到最后的写入时间。见***.com/questions/9992223/… 如何获得真正的修改时间?我的意思是即使在没有实际更改的情况下进行简单的重新保存,此属性也会发生变化。有什么方法可以检测到虚假更改? @MehdiDehghani 检查文件是否真的被更改的一个好方法是检查校验和。校验和仅在文件内容更改时才会更改,请参阅***.com/questions/10520048/…【参考方案2】:

只需使用File.GetLastWriteTime。该页面上有一个示例显示如何使用它。

【讨论】:

不幸的是,File.GetLastWriteTime 并不总是获得最后的写入时间。这似乎是一个很好的解决方案,直到您意识到内部缓存在接近 GetLastWriteTime 似乎提供的精度的任何地方都不准确。见***.com/questions/9992223/…【参考方案3】:

您只需要 File.GetLastWriteTime 静态方法。

例子:

var lastModified = System.IO.File.GetLastWriteTime("C:\foo.bar");

Console.WriteLine(lastModified.ToString("dd/MM/yy HH:mm:ss"));

但是请注意,在极少数情况下,系统不会在写入文件时更新最后修改时间(这可能是为了优化高频写入,例如日志记录或作为错误而有意发生的),然后这种方法会失败,您将需要从系统订阅文件写入通知,并不断监听。

【讨论】:

赞成花时间包含代码示例。 很遗憾这里的许多答案都说 GetLastWriteTime。不幸的是,它没有按照它所说的去做——它没有得到最后的写入时间。唯一可以确定的方法是积极观察文件更改。 ***.com/questions/9992223/… @gburton 当然可以!只有写入文件而不更新最后修改时间的程序(这是非常不标准的)才会导致这种方法出现问题。 @gburton 显然。但是你错过了整个要点:仅仅因为它在你奇怪的情况下不起作用,并不意味着它在大多数情况下不起作用。你的是例外,而不是规则。它违反了惯例。 @Noldorin 我的“奇怪案例”实际上是一个 .net 4.5 Web 应用程序,据说没有正确更新时间戳的工具(不应该是手动操作)是角度命令线工具。这些是完全正常的情况;这是微软的一项性能优化,它使 GetLastWriteTime 无用。检查这个 SO 线程:***.com/a/4381256/3931173【参考方案4】:

请注意,函数 File.GetLastWriteTime 并不总是按预期工作,操作系统有时不会立即更新这些值。您可能会得到一个旧的时间戳,即使该文件之前已被修改过。

该行为可能因操作系统版本而异。例如,这个单元测试在我的开发机器上每次都运行良好,但在我们的构建服务器上总是失败。

  [TestMethod]
  public void TestLastModifiedTimeStamps()
  
     var tempFile = Path.GetTempFileName();
     var lastModified = File.GetLastWriteTime(tempFile);
     using (new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.None))
     

     
     Assert.AreNotEqual(lastModified, File.GetLastWriteTime(tempFile));
  

见File.GetLastWriteTime seems to be returning 'out of date' value

您的选择:

a) 忍受偶尔的遗漏。

b) 构建一个实现观察者模式的活动组件(例如 tcp 服务器客户端结构),直接传达更改而不是写入/读取文件。快速且灵活,但另一种依赖性和可能的​​故障点(当然还有一些工作)。

c) 通过替换其他进程定期读取的专用信号文件的内容来确保信号进程。它不是那么聪明,因为它是一个轮询过程,并且比调用 File.GetLastWriteTime 的开销更大,但如果不经常检查来自太多地方的内容,它会完成这项工作。

/// <summary>
/// type to set signals or check for them using a central file 
/// </summary>
public class FileSignal

    /// <summary>
    /// path to the central file for signal control
    /// </summary>
    public string FilePath  get; private set; 

    /// <summary>
    /// numbers of retries when not able to retrieve (exclusive) file access
    /// </summary>
    public int MaxCollisions  get; private set; 

    /// <summary>
    /// timespan to wait until next try
    /// </summary>
    public TimeSpan SleepOnCollisionInterval  get; private set; 

    /// <summary>
    /// Timestamp of the last signal
    /// </summary>
    public DateTime LastSignal  get; private set; 

    /// <summary>
    /// constructor
    /// </summary>
    /// <param name="filePath">path to the central file for signal control</param>
    /// <param name="maxCollisions">numbers of retries when not able to retrieve (exclusive) file access</param>
    /// <param name="sleepOnCollisionInterval">timespan to wait until next try </param>
    public FileSignal(string filePath, int maxCollisions, TimeSpan sleepOnCollisionInterval)
    
        FilePath = filePath;
        MaxCollisions = maxCollisions;
        SleepOnCollisionInterval = sleepOnCollisionInterval;
        LastSignal = GetSignalTimeStamp();
    

    /// <summary>
    /// constructor using a default value of 50 ms for sleepOnCollisionInterval
    /// </summary>
    /// <param name="filePath">path to the central file for signal control</param>
    /// <param name="maxCollisions">numbers of retries when not able to retrieve (exclusive) file access</param>        
    public FileSignal(string filePath, int maxCollisions): this (filePath, maxCollisions, TimeSpan.FromMilliseconds(50))
    
    

    /// <summary>
    /// constructor using a default value of 50 ms for sleepOnCollisionInterval and a default value of 10 for maxCollisions
    /// </summary>
    /// <param name="filePath">path to the central file for signal control</param>        
    public FileSignal(string filePath) : this(filePath, 10)
    
    

    private Stream GetFileStream(FileAccess fileAccess)
    
        var i = 0;
        while (true)
        
            try
            
                return new FileStream(FilePath, FileMode.Create, fileAccess, FileShare.None);
            
            catch (Exception e)
            
                i++;
                if (i >= MaxCollisions)
                
                    throw e;
                
                Thread.Sleep(SleepOnCollisionInterval);
            ;
        ;
    

    private DateTime GetSignalTimeStamp()
    
        if (!File.Exists(FilePath))
        
            return DateTime.MinValue;
        
        using (var stream = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.None))
        
            if(stream.Length == 0)
            
                return DateTime.MinValue;
            
            using (var reader = new BinaryReader(stream))
            
                return DateTime.FromBinary(reader.ReadInt64());
            ;                
        
    

    /// <summary>
    /// overwrites the existing central file and writes the current time into it.
    /// </summary>
    public void Signal()
    
        LastSignal = DateTime.Now;
        using (var stream = new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.None))
        
            using (var writer = new BinaryWriter(stream))
            
                writer.Write(LastSignal.ToBinary());
            
        
    

    /// <summary>
    /// returns true if the file signal has changed, otherwise false.
    /// </summary>        
    public bool CheckIfSignalled()
    
        var signal = GetSignalTimeStamp();
        var signalTimestampChanged = LastSignal != signal;
        LastSignal = signal;
        return signalTimestampChanged;
    

一些测试:

    [TestMethod]
    public void TestSignal()
    
        var fileSignal = new FileSignal(Path.GetTempFileName());
        var fileSignal2 = new FileSignal(fileSignal.FilePath);
        Assert.IsFalse(fileSignal.CheckIfSignalled());
        Assert.IsFalse(fileSignal2.CheckIfSignalled());
        Assert.AreEqual(fileSignal.LastSignal, fileSignal2.LastSignal);
        fileSignal.Signal();
        Assert.IsFalse(fileSignal.CheckIfSignalled());
        Assert.AreNotEqual(fileSignal.LastSignal, fileSignal2.LastSignal);
        Assert.IsTrue(fileSignal2.CheckIfSignalled());
        Assert.AreEqual(fileSignal.LastSignal, fileSignal2.LastSignal);
        Assert.IsFalse(fileSignal2.CheckIfSignalled());
    

【讨论】:

我的单元测试遇到了完全相同的问题。由于我正在测试的代码逻辑并不简单,我花了几天时间才发现上次修改时间不准确。

以上是关于在 C# 中检查文件的最后修改日期的主要内容,如果未能解决你的问题,请参考以下文章

在Linux中如何查看文件的修改日期

如何在 Go 中获取文件的最后访问日期和时间?

在 C# 中检查贝宝订阅状态

检查文件系统上文件的修改日期并获取最新文件

C ++如何检查文件的最后修改时间

获取 Blob 存储的最后修改日期