web-dev-qa-db-fra.com

Vérifier la dernière date de modification du fichier en C #

Je cherche une façon de voir quand un fichier a été modifié pour la dernière fois en C #. J'ai un accès complet au fichier.

54
Candyfloss

System.IO.File.GetLastWriteTime est ce dont vous avez besoin.

95
Dean Harding

Vous voulez simplement le File.GetLastWriteTime méthode statique.

Exemple:

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

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

Notez cependant que dans le cas rare, la dernière heure modifiée n'est pas mise à jour par le système lors de l'écriture dans le fichier (cela peut se produire intentionnellement comme une optimisation pour l'écriture à haute fréquence, par exemple la journalisation ou comme bogue), alors cette approche échouer, et vous devrez à la place vous abonner aux notifications d'écriture de fichiers du système, en écoutant constamment.

56
Noldorin

Sachez que la fonction File.GetLastWriteTime ne fonctionne pas toujours comme prévu, les valeurs ne sont parfois pas mises à jour instantanément par l'OS. Vous pouvez obtenir un ancien horodatage, même si le fichier a été modifié juste avant.

Le comportement peut varier entre les versions du système d'exploitation. Par exemple, ce test unitaire a bien fonctionné à chaque fois sur ma machine de développeur, mais il échoue toujours sur notre serveur de build.

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

Voir File.GetLastWriteTime semble renvoyer la valeur 'obsolète'

Vos options:

a) vivre avec les omissions occasionnelles.

b) Construire un composant actif réalisant le modèle d'observateur (par exemple une structure client de serveur TCP), communiquant les changements directement au lieu d'écrire/lire des fichiers. Rapide et flexible, mais une autre dépendance et un éventuel point de défaillance (et certains travaux, bien sûr).

c) Assurer le processus de signalisation en remplaçant le contenu d'un fichier de signal dédié que d'autres processus lisent régulièrement. Ce n'est pas aussi intelligent que c'est une procédure d'interrogation et a un temps système plus important que d'appeler File.GetLastWriteTime, mais s'il ne vérifie pas le contenu trop souvent, il fera le travail.

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

Quelques tests pour cela:

    [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());
    }
19
Udontknow

Utilisez simplement File.GetLastWriteTime . Il y a un exemple sur cette page montrant comment l'utiliser.

4
Hans Olsson