C# FileSystemWatcher 監視檔案變更 去除重複

上一篇FileSystemWatcher 監視資料夾和檔案變更

有提到同個變更可能會呼叫數次,這裡就使用ListLINQ來解決

寫個類別紀錄檔案路徑和時間,放在List裡面,超過30秒就從清單中移除

因為我們只是要避免幾十毫秒內的重複觸發,所以其實也可以不用那麼久

private FileSystemWatcher _fileSystemWatcher;
private string monitorPath = "D:\\";

public void Monitor()
{
try
{
if (_fileSystemWatcher == null) _fileSystemWatcher = new FileSystemWatcher();

_fileSystemWatcher.Path = monitorPath;
_fileSystemWatcher.NotifyFilter =
NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.CreationTime;

_fileSystemWatcher.IncludeSubdirectories = false;
_fileSystemWatcher.EnableRaisingEvents = true;


_fileSystemWatcher.Changed += FileChanged; //檔案屬性變更、建立的檔案和刪除的檔案
_fileSystemWatcher.Renamed += FileChanged; //重新命名檔案和資料夾的舊路徑和新路徑
}
catch (Exception exception)
{
}
}

List<FileRecord> _fileRecords = new List<FileRecord>();

private void FileChanged(object sender, FileSystemEventArgs e)
{
string filePath = e.FullPath;


//清理紀錄,移除30秒前紀錄
_fileRecords.RemoveAll(a => a.ChangeTime.AddSeconds(30) < DateTime.Now);

//依照檔案路徑查詢
var file =
from Obsolete in _fileRecords
where Obsolete.FilePath.Equals(filePath)
select Obsolete;

//如果有一樣的檔案
if (file.Any())
{
Console.WriteLine("重複變動的檔案:" + filePath);
}
else
{
Console.WriteLine("第一次變動的檔案:" + filePath);
_fileRecords.Add(new FileRecord(filePath));
}
}

class FileRecord
{
public string FilePath;
public DateTime ChangeTime;

public FileRecord(string filePath)
{
FilePath = filePath;
ChangeTime = DateTime.Now;
}
}


這裡用的方式就還不錯,用RemoveAll直接移除,比foreach還快

今天改客戶需求的時候也用LINQ想到的

附上程式碼截圖:


註:後來和老闆討論的時候有談到某些可能的原因,所以可能不用這麼麻煩,只要寫一個字串,判斷內容和現在的檔名一樣就跳過,不一樣則塞進去然後處理就可以了。

但是沒有進行大規模測試,怕軟體交付後才出現問題,所以我暫時是用上面提供的方式

如果大家有比較好的做法或是測試結果,都歡迎留言告訴我,謝謝!


留言

  1. 感謝提供思路,
    我把[清理紀錄,移除30秒前紀錄]這行的RemoveAll判斷,改換到 if (file.Any()) 區塊內,
    避免每次即使沒有重複也在進行多餘的刪除動作

    回覆刪除
    回覆
    1. 現在回頭看自己以前寫的程式碼,有許多細節都沒有注意到
      非常感謝您的建議!讓我有修正文章的機會

      刪除

張貼留言

如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com