我有一个应用程序,我正在寻找一个文本文件,如果对文件做了任何更改,我使用OnChanged事件处理程序来处理事件。我正在使用NotifyFilters。LastWriteTime,但是事件仍然被触发两次。这是代码。

public void Initialize()
{
   FileSystemWatcher _fileWatcher = new FileSystemWatcher();
  _fileWatcher.Path = "C:\\Folder";
  _fileWatcher.NotifyFilter = NotifyFilters.LastWrite;
  _fileWatcher.Filter = "Version.txt";
  _fileWatcher.Changed += new FileSystemEventHandler(OnChanged);
  _fileWatcher.EnableRaisingEvents = true;
}

private void OnChanged(object source, FileSystemEventArgs e)
{
   .......
}

在我的情况下,OnChanged被调用两次,当我改变文本文件version.txt并保存它。


当前回答

好吧,这是我如何只引发一个事件的解决方案:

FileSystemWatcheк watcher = new FileSystemWatcher();

//'path' - path to the file that has been modified.
watcher.Changed += (s, e) => FileChanged(path);

这里是FileChanged实现

//count is our counter to triger when we can raise and when not.
private int count = 0;
private void FileChanged(string path)
{
   if (count % 2 == 0)
     {
       //code here
     }

     count ++;
}

其他回答

我在这里有一个非常快速和简单的解决方法,它对我来说确实有效,无论事件偶尔会被触发一次或两次或多次,检查它:

private int fireCount = 0;
private void inputFileWatcher_Changed(object sender, FileSystemEventArgs e)
    {
       fireCount++;
       if (fireCount == 1)
        {
            MessageBox.Show("Fired only once!!");
            dowork();
        }
        else
        {
            fireCount = 0;
        }
    }
}

我改变了监视目录中的文件的方式。我没有使用FileSystemWatcher,而是在另一个线程上轮询位置,然后查看文件的LastWriteTime。

DateTime lastWriteTime = File.GetLastWriteTime(someFilePath);

使用这些信息并保持文件路径的索引和最近的写入时间,我可以确定在特定位置已更改或已创建的文件。这使我摆脱了FileSystemWatcher的奇怪之处。主要的缺点是您需要一个数据结构来存储LastWriteTime和对文件的引用,但是它是可靠且易于实现的。

我知道这是一个老问题,但我遇到了同样的问题,上面的解决方案都没有真正解决我所面临的问题。我已经创建了一个字典,它将文件名与LastWriteTime映射。因此,如果文件不在字典中,将继续执行该进程,否则将检查最后一次修改时间是什么时候,如果与字典中的时间不同,则运行代码。

    Dictionary<string, DateTime> dateTimeDictionary = new Dictionary<string, DateTime>(); 

        private void OnChanged(object source, FileSystemEventArgs e)
            {
                if (!dateTimeDictionary.ContainsKey(e.FullPath) || (dateTimeDictionary.ContainsKey(e.FullPath) && System.IO.File.GetLastWriteTime(e.FullPath) != dateTimeDictionary[e.FullPath]))
                {
                    dateTimeDictionary[e.FullPath] = System.IO.File.GetLastWriteTime(e.FullPath);

                    //your code here
                }
            }

这是另一种方法。现在,除了最后一个事件以外,所有事件都被抑制,而不是传播一系列事件中的第一个事件并抑制所有接下来的事件。我认为可以从这种方法中受益的场景更常见。

要做到这一点,我们必须使用滑动延迟。每个传入事件都会取消触发前一个事件的计时器,并重新启动计时器。这开启了一种可能性,即一系列永无止境的事件将永远推迟传播。为了简单起见,在下面的扩展方法中没有针对这种异常情况的规定。

public static class FileSystemWatcherExtensions
{
    public static IDisposable OnAnyEvent(this FileSystemWatcher source,
        WatcherChangeTypes changeTypes, FileSystemEventHandler handler, int delay)
    {
        var cancellations = new Dictionary<string, CancellationTokenSource>(
            StringComparer.OrdinalIgnoreCase);
        var locker = new object();
        if (changeTypes.HasFlag(WatcherChangeTypes.Created))
            source.Created += FileSystemWatcher_Event;
        if (changeTypes.HasFlag(WatcherChangeTypes.Deleted))
            source.Deleted += FileSystemWatcher_Event;
        if (changeTypes.HasFlag(WatcherChangeTypes.Changed))
            source.Changed += FileSystemWatcher_Event;
        if (changeTypes.HasFlag(WatcherChangeTypes.Renamed))
            source.Renamed += FileSystemWatcher_Event;
        return new Disposable(() =>
        {
            source.Created -= FileSystemWatcher_Event;
            source.Deleted -= FileSystemWatcher_Event;
            source.Changed -= FileSystemWatcher_Event;
            source.Renamed -= FileSystemWatcher_Event;
        });

        async void FileSystemWatcher_Event(object sender, FileSystemEventArgs e)
        {
            var key = e.FullPath;
            var cts = new CancellationTokenSource();
            lock (locker)
            {
                if (cancellations.TryGetValue(key, out var existing))
                {
                    existing.Cancel();
                }
                cancellations[key] = cts;
            }
            try
            {
                await Task.Delay(delay, cts.Token);
                // Omitting ConfigureAwait(false) is intentional here.
                // Continuing in the captured context is desirable.
            }
            catch (TaskCanceledException)
            {
                return;
            }
            lock (locker)
            {
                if (cancellations.TryGetValue(key, out var existing)
                    && existing == cts)
                {
                    cancellations.Remove(key);
                }
            }
            cts.Dispose();
            handler(sender, e);
        }
    }

    public static IDisposable OnAllEvents(this FileSystemWatcher source,
        FileSystemEventHandler handler, int delay)
        => OnAnyEvent(source, WatcherChangeTypes.All, handler, delay);

    public static IDisposable OnCreated(this FileSystemWatcher source,
        FileSystemEventHandler handler, int delay)
        => OnAnyEvent(source, WatcherChangeTypes.Created, handler, delay);

    public static IDisposable OnDeleted(this FileSystemWatcher source,
        FileSystemEventHandler handler, int delay)
        => OnAnyEvent(source, WatcherChangeTypes.Deleted, handler, delay);

    public static IDisposable OnChanged(this FileSystemWatcher source,
        FileSystemEventHandler handler, int delay)
        => OnAnyEvent(source, WatcherChangeTypes.Changed, handler, delay);

    public static IDisposable OnRenamed(this FileSystemWatcher source,
        FileSystemEventHandler handler, int delay)
        => OnAnyEvent(source, WatcherChangeTypes.Renamed, handler, delay);

    private struct Disposable : IDisposable
    {
        private readonly Action _action;
        internal Disposable(Action action) => _action = action;
        public void Dispose() => _action?.Invoke();
    }
}

使用的例子:

myWatcher.OnAnyEvent(WatcherChangeTypes.Created | WatcherChangeTypes.Changed,
    MyFileSystemWatcher_Event, 100);

这一行将两个事件(Created和Changed)的订阅组合在一起。所以它大致相当于这些:

myWatcher.Created += MyFileSystemWatcher_Event;
myWatcher.Changed += MyFileSystemWatcher_Event;

不同之处在于,这两个事件被视为单一类型的事件,在这些事件快速连续的情况下,只有最后一个事件将被传播。例如,如果一个Created事件后面跟着两个Changed事件,并且这三个事件之间的时间间隔不超过100 msec,则只有第二个Changed事件将通过调用MyFileSystemWatcher_Event处理程序来传播,而前一个事件将被丢弃。

FileReadTime = DateTime.Now;

private void File_Changed(object sender, FileSystemEventArgs e)
{            
    var lastWriteTime = File.GetLastWriteTime(e.FullPath);
    if (lastWriteTime.Subtract(FileReadTime).Ticks > 0)
    {
        // code
        FileReadTime = DateTime.Now;
    }
}