簡體   English   中英

FileSystemWatcher:忽略對文件的第一次更改

[英]FileSystemWatcher: Ignore first change to the file

我在C#中使用FileSystemWatcher類來跟蹤用戶在修改文件后保存文件時的更改。

FileSystemWatcher watcher = new FileSystemWatcher()
{
    Path = DIR_NAME,
    NotifyFilter = NotifyFilters.LastWrite | 
                   NotifyFilters.CreationTime | 
                   NotifyFilters.LastAccess,
    Filter = "*.pdf",
    IncludeSubdirectories = true,
    EnableRaisingEvents = true
};

watcher.Changed += OnChanged;

但是,我要跟蹤的文件是以編程方式創建的,如下所示:

FileStream stream = FileUtil.CreateNewFile(filePath); // Creates a file
file.WriteFileToStream(stream); // Writes into the file

理想情況下,我的代碼應該按如下方式運行:

  1. 該程序將創建一個文件並向其中寫入一些內容。
  2. 用戶打開文件,修改並保存。
  3. 此時,它應該觸發OnChanged ,即我希望我的OnChanged處理程序代碼僅在真實用戶修改並保存它時執行。

但是,只要以編程方式寫入文件,它就會被觸發,即在以下行中:

file.WriteFileToStream(stream);

從技術上講,這是正確的行為,因為它正在跟蹤文件中的更改。 但是,我的業務案例不允許在最初創建和寫入文件時執行OnChanged處理程序代碼。

我的問題是,是否有一種解決方法可以在第一次以編程方式創建和寫入文件時跳過OnChanged調用?

筆記:

  1. 應用程序架構要求在我的應用程序啟動時初始化FileSystemWatcher 所以我無法在創建文件后注冊它。
  2. 這是一個多用戶應用程序,其中多個用戶將同時寫入文件,因此我無法在創建文件之前禁用觀察器並在創建文件后啟用它:

watcher.EnableRaisingEvents = false; 
CreateFile();
watcher.EnableRaisingEvents = true;

方法一:

  1. 創建文件並將其保存在未被監視的目錄中。
  2. 將文件移動到正在監視的目錄中。

方法二:

創建文件時,使用OnCreated()事件處理程序將文件名添加到filesToIgnore列表。

OnChanged事件處理程序中,檢查filesToIgnore列表是否包含文件名。 如果是,則將其從列表中刪除(以便下次處理)並從處理程序返回。

private List<string> filesToIgnore = new List<string>();

private void OnCreated(object source, FileSystemEventArgs file)
{
   filesToIgnore.Add(file.Name);
}

private void OnChanged(object source, FileSystemEventArgs file)
{
    if(filesToIgnore.Contains(file.Name))
    {
         filesToIgnore.Remove(file.Name);
         return; 
    }

    // Code to execute when user saves the file
}

此方法假定OnCreated()將始終在OnChanged().

這是一個棘手的情況,除了檢查文件是否被鎖定(假設它有讀鎖或寫鎖)之外,您無能為力:

public  bool IsFileLocked(string fileName)
{

   try
   {
      using (var stream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.None))
      {
         return false;
      }   
   }
   catch (IOException)
   {
      //the file is unavailable
      return true;
   }
}

前提是當你獲得更新時,你檢查文件是否被鎖定,如果不是那么你可以粗略地假設它已被關閉。

但需要考慮一些事項:

  1. 當檢查文件是否被鎖定、清除所有內容,然后發現其他進程已鎖定該文件時,可能存在競爭條件。
  2. 我使用過FileAccess.Read ,所以這不會在只讀文件上失敗。
  3. 由於各種原因,事件可能會從FileSystemWatcher中刪除,並且在某些情況下不能總是依賴它; 閱讀文檔以了解可以刪除事件的原因以及如何修復它們。 在這些情況下,您可以通過長時間的輪詢和一些邏輯來挑選掉隊的人(取決於您的情況)。

我在OnChanged處理程序中添加了以下代碼,它似乎按預期工作。

private void OnChanged(object source, FileSystemEventArgs file)
{
    if (file.ChangeType == WatcherChangeTypes.Created)
        return;

    FileInfo fileInfo = new FileInfo(file.FullPath);
    if (fileInfo.CreationTime == fileInfo.LastWriteTime)
        return; 

    // Handle the Changed event
    ...
}

但是,我不確定我是否遺漏了一些會導致它崩潰的東西。 有什么想法嗎?

下面的擴展方法只允許處理來自用戶操作的事件:

public static void OnChangedByUser(this FileSystemWatcher fsw,
    FileSystemEventHandler handler)
{
    const int TOLERANCE_MSEC = 100;
    object locker = new object();
    string fileName = null;
    Stopwatch stopwatch = new Stopwatch();
    fsw.Created += OnFileCreated;
    fsw.Changed += OnFileChanged;
    fsw.Disposed += OnDisposed;
    void OnFileCreated(object sender, FileSystemEventArgs e)
    {
        lock (locker)
        {
            fileName = e.Name;
            stopwatch.Restart();
        }
    }
    void OnFileChanged(object sender, FileSystemEventArgs e)
    {
        lock (locker)
        {
            if (e.Name == fileName && stopwatch.ElapsedMilliseconds < TOLERANCE_MSEC)
            {
                return; // Ignore this event
            }
        }
        handler.Invoke(sender, e);
    }
    void OnDisposed(object sender, EventArgs e)
    {
        fsw.Created -= OnFileCreated;
        fsw.Changed -= OnFileChanged;
        fsw.Disposed -= OnDisposed;
    }
}

使用示例:

var fsw = new FileSystemWatcher(DIR_NAME);
fsw.OnChangedByUser(File_ChangedByUser);
fsw.EnableRaisingEvents = true;

private static void File_ChangedByUser(object sender, FileSystemEventArgs e)
{
    // Handle the event
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM