web-dev-qa-db-ja.com

C#でファイルの最終変更日を確認する

ファイルがC#で最後に変更された日時を確認する方法を探しています。ファイルへのフルアクセスがあります。

54
Candyfloss
95
Dean Harding

File.GetLastWriteTime 静的メソッド。

例:

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

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

ただし、まれに、ファイルへの書き込み時に最終変更時刻がシステムによって更新されないことに注意してください(これは、ロギングやバグなどの高頻度書き込みの最適化として意図的に発生することがあります)。失敗し、代わりにシステムからのファイル書き込み通知をサブスクライブし、常にリッスンする必要があります。

56
Noldorin

関数File.GetLastWriteTimeは常に期待どおりに動作するとは限らないことに注意してください。OSによって値が瞬時に更新されない場合があります。ファイルが直前に変更された場合でも、古いタイムスタンプが表示される場合があります。

動作はOSバージョンによって異なる場合があります。たとえば、この単体テストは開発者のマシンでは毎回うまく機能しましたが、ビルドサーバーでは常に失敗します。

  [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は「期限切れ」の値を返しているようです を参照してください

あなたのオプション:

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

File.GetLastWriteTime を使用するだけです。そのページには、使用方法を示すサンプルがあります。

4
Hans Olsson