我有一个应用程序,我正在寻找一个文本文件,如果对文件做了任何更改,我使用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并保存它。


当前回答

这个代码对我有用。

        private void OnChanged(object source, FileSystemEventArgs e)
    {

        string fullFilePath = e.FullPath.ToString();
        string fullURL = buildTheUrlFromStudyXML(fullFilePath);

        System.Diagnostics.Process.Start("iexplore", fullURL);

        Timer timer = new Timer();
        ((FileSystemWatcher)source).Changed -= new FileSystemEventHandler(OnChanged);
        timer.Interval = 1000;
        timer.Elapsed += new ElapsedEventHandler(t_Elapsed);
        timer.Start();
    }

    private void t_Elapsed(object sender, ElapsedEventArgs e)
    {
        ((Timer)sender).Stop();
        theWatcher.Changed += new FileSystemEventHandler(OnChanged);
    }

其他回答

FileSystemWatcher中的任何重复的OnChanged事件都可以通过检查File来检测和丢弃。GetLastWriteTime文件的时间戳。像这样:

DateTime lastRead = DateTime.MinValue;

void OnChanged(object source, FileSystemEventArgs a)
{
    DateTime lastWriteTime = File.GetLastWriteTime(uri);
    if (lastWriteTime != lastRead)
    {
        doStuff();
        lastRead = lastWriteTime;
    }
    // else discard the (duplicated) OnChanged event
}

我知道这是一个老问题,但我遇到了同样的问题,上面的解决方案都没有真正解决我所面临的问题。我已经创建了一个字典,它将文件名与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
                }
            }

我们可以这么简单。这对我很管用。

private static void OnChanged(object sender, FileSystemEventArgs e) 
{
    if (File.GetAttributes(e.FullPath) == FileAttributes.Directory)
        return;
    double timeSpan = DateTime.Now.Subtract(File.GetLastWriteTime(e.FullPath)).TotalSeconds;
    if (timeSpan > 1)
        return;
    Console.WriteLine($"Changed: {e.FullPath}");
}

我已经在我的委托中使用以下策略“修复”了这个问题:

// fsw_ is the FileSystemWatcher instance used by my application.

private void OnDirectoryChanged(...)
{
   try
   {
      fsw_.EnableRaisingEvents = false;

      /* do my stuff once asynchronously */
   }

   finally
   {
      fsw_.EnableRaisingEvents = true;
   }
}

代码可自定义禁用阻止第二个观察者升起的时间间隔,如果他们存在,则不阻止观察者:

    namespace Watcher
    {
        class Static
        {
            public static DateTime lastDomain { get; set; }
            public static string lastDomainStr { get; set; }
        }
        public partial class Form1 : Form
       {
            int minMs = 20;//time for blocking in ms
            public Form1()
            {
                InitializeComponent();
                Static.lastDomain = new DateTime(1970, 1, 1, 0, 0, 0);
                Static.lastDomainStr = "";  
                Start();
            }
             private void Start()//Start watcher
             {
                //...
                domain.Changed += new FileSystemEventHandler(Domain);
                domain.EnableRaisingEvents = true;
                //...you second unblocked watchers
                second.Changed += new FileSystemEventHandler(Second);
                second.EnableRaisingEvents = true;
             }
             private void Domain(object source, FileSystemEventArgs e)
             {
                if (now.Subtract(Static.lastDomain).TotalMilliseconds < minMs && Static.lastDomainStr == e.FullPath)return;
                 //...you code here
                 /* if you need form access
                 this.Invoke(new MethodInvoker(() =>{ textBox1.Text = "...";}));
                 */
                 Static.lastDomain = DateTime.Now;
                 Static.lastDomainStr = e.FullPath;
             }
             private void Second(object source, FileSystemEventArgs e)
             {
                  //...Second rised
             }
       }
    }