C# 检查C中文件的上次修改日期#
我想找出一种方法来查看文件最后一次在C#中被修改的时间。我可以完全访问该文件。是您需要的。只需使用即可。该页面上有一个示例,展示了如何使用它。您只需要静态方法 例如:C# 检查C中文件的上次修改日期#,c#,windows,file,last-modified,C#,Windows,File,Last Modified,我想找出一种方法来查看文件最后一次在C#中被修改的时间。我可以完全访问该文件。是您需要的。只需使用即可。该页面上有一个示例,展示了如何使用它。您只需要静态方法 例如: var lastModified = System.IO.File.GetLastWriteTime("C:\foo.bar"); Console.WriteLine(lastModified.ToString("dd/MM/yy HH:mm:ss")); 但是请注意,在极少数情况下,系
var lastModified = System.IO.File.GetLastWriteTime("C:\foo.bar");
Console.WriteLine(lastModified.ToString("dd/MM/yy HH:mm:ss"));
但是请注意,在极少数情况下,系统在写入文件时不会更新上次修改的时间(这可能是为了优化高频写入,例如日志记录,或是作为一个bug),那么这种方法将失败,您将需要从系统订阅文件写入通知,持续监听。请注意,函数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));
}
看
您的选择:
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;
}
}
以上链接中问题的可能重复是针对更具体的情况,但我同意-该问题中提到了此处已接受的答案。请投票支持花时间包含代码示例。遗憾的是,此处的许多答案都说GetLastWriteTime。不幸的是,它没有做到它所说的-它没有得到最后的写入时间。确保的唯一方法是积极观察文件更改@格伯顿:的确如此!只有在没有更新上次修改时间(这是非常不标准的)的情况下写入文件的程序才会导致这种方法出现问题。@gburton。但是你忽略了全部要点:仅仅因为它在你奇怪的情况下不起作用,并不意味着它在大多数情况下不起作用。你的是例外,不是规则。它违反了惯例。@Noldorin我的“wierd case”实际上是一个.net 4.5 web应用程序,而据推测没有正确更新时间戳的工具(不应是手动操作)是angular命令行工具。这是完全正常的情况,;这是微软的性能优化,使得GetLastWriteTime毫无用处。检查此线程:或者甚至可能是令人伤心的事实-GetLastWriteTime没有获得最后一次写入时间。查看如何获得实时修改?我的意思是,即使在没有实际更改的情况下进行简单的重新保存,此属性也会更改。有没有办法检测到虚假更改?@MehdiDehghani检查文件是否真的更改的一个好方法是检查校验和。仅当文件内容更改时,校验和才会更改。请注意,file.GetLastWriteTime并不总是获取最后一次写入时间。这似乎是一个很好的解决方案,直到您意识到存在内部缓存,它们的精度无法接近GetLastWriteTime提供的精度。看,我在单元测试中遇到了完全相同的问题。由于我正在测试的代码逻辑并不简单,我花了好几天的时间才发现上次修改的时间并不准确。
[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());
}