[英]FileSystemWatcher Fires Event After Second Change, But Not First
[英]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
理想情況下,我的代碼應該按如下方式運行:
OnChanged
,即我希望我的OnChanged
處理程序代碼僅在真實用戶修改並保存它時執行。但是,只要以編程方式寫入文件,它就會被觸發,即在以下行中:
file.WriteFileToStream(stream);
從技術上講,這是正確的行為,因為它正在跟蹤文件中的更改。 但是,我的業務案例不允許在最初創建和寫入文件時執行OnChanged
處理程序代碼。
我的問題是,是否有一種解決方法可以在第一次以編程方式創建和寫入文件時跳過OnChanged
調用?
筆記:
FileSystemWatcher
。 所以我無法在創建文件后注冊它。watcher.EnableRaisingEvents = false;
CreateFile();
watcher.EnableRaisingEvents = true;
方法一:
方法二:
創建文件時,使用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;
}
}
前提是當你獲得更新時,你檢查文件是否被鎖定,如果不是那么你可以粗略地假設它已被關閉。
但需要考慮一些事項:
FileAccess.Read
,所以這不會在只讀文件上失敗。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.