跳过重复数据太冒险了,因为代码可能会看到不完整的数据版本。
相反,我们可以等待指定的合并毫秒数,直到没有更改为止。
重要提示:下面的示例仅适用于当您想要在一个或多个文件更改时收到单个通知的情况。其中一个原因是它硬编码了NotifyFilter,这可以修改以允许更改。另一个原因是它不告诉您哪些文件已更改或更改的类型(FileSystemEventArgs),这也可以修改以提供检测到的所有更改列表。
一个很大的缺点是,如果文件更新的频率超过合并毫秒数,则不会触发。
private sealed class SingleFireFilesWatcher : IDisposable
{
public event EventHandler? Changed;
private readonly FileSystemWatcher watcher;
private bool disposed;
public SingleFireFilesWatcher(int mergeMilliseconds, params string[] filters)
{
var timer = new Timer(_ => Changed?.Invoke(this, EventArgs.Empty));
watcher = new FileSystemWatcher();
foreach (var filter in filters)
watcher.Filters.Add(filter);
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Changed += (s, e) => timer.Change(mergeMilliseconds, Timeout.Infinite);
watcher.EnableRaisingEvents = true;
}
public void Dispose()
{
if (disposed) return;
disposed = true;
watcher.Dispose();
}
}
解决上述限制的方法是始终在第一次更改后触发合并毫秒。代码只稍微复杂一些。
其中一个缺点是,如果mergeMilliseconds设置得非常低,您可能会获得大量额外的触发。
private sealed class SingleFireFilesWatcher2 : IDisposable
{
public event EventHandler? Changed;
private readonly FileSystemWatcher watcher;
private bool disposed;
public SingleFireFilesWatcher2(int mergeMilliseconds, params string[] filters)
{
var restartTimerOnNextChange = true;
var timer = new Timer(_ =>
{
restartTimerOnNextChange = true;
Changed?.Invoke(this, EventArgs.Empty);
});
watcher = new FileSystemWatcher();
foreach (var filter in filters)
watcher.Filters.Add(filter);
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Changed += (s, e) =>
{
if (restartTimerOnNextChange)
timer.Change(mergeMilliseconds, Timeout.Infinite);
restartTimerOnNextChange = false;
};
watcher.EnableRaisingEvents = true;
}
public void Dispose()
{
if (disposed) return;
disposed = true;
watcher.Dispose();
}
}