FileSystemWatcher Changed event is raised twice

前端 未结 30 3197
死守一世寂寞
死守一世寂寞 2020-11-22 06:01

I have an application where I am looking for a text file and if there are any changes made to the file I am using the OnChanged eventhandler to handle the event

相关标签:
30条回答
  • 2020-11-22 06:20

    I am afraid that this is a well-known bug/feature of the FileSystemWatcher class. This is from the documentation of the class:

    You may notice in certain situations that a single creation event generates multiple Created events that are handled by your component. For example, if you use a FileSystemWatcher component to monitor the creation of new files in a directory, and then test it by using Notepad to create a file, you may see two Created events generated even though only a single file was created. This is because Notepad performs multiple file system actions during the writing process. Notepad writes to the disk in batches that create the content of the file and then the file attributes. Other applications may perform in the same manner. Because FileSystemWatcher monitors the operating system activities, all events that these applications fire will be picked up.

    Now this bit of text is about the Created event, but the same thing applies to other file events as well. In some applications you might be able to get around this by using the NotifyFilter property, but my experience is says that sometimes you have to do some manual duplicate filtering (hacks) as well.

    A while ago I bookedmarked a page with a few FileSystemWatcher tips. You might want to check it out.

    0 讨论(0)
  • 2020-11-22 06:20

    The main reason was first event's last access time was current time(file write or changed time). then second event was file's original last access time. I solve under code.

            var lastRead = DateTime.MinValue;
    
            Watcher = new FileSystemWatcher(...)
            {
                NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite,
                Filter = "*.dll",
                IncludeSubdirectories = false,
            };
            Watcher.Changed += (senderObject, ea) =>
            {
                var now = DateTime.Now;
                var lastWriteTime = File.GetLastWriteTime(ea.FullPath);
    
                if (now == lastWriteTime)
                {
                    return;
                }
    
                if (lastWriteTime != lastRead)
                {
                    // do something...
                    lastRead = lastWriteTime;
                }
            };
    
            Watcher.EnableRaisingEvents = true;
    
    0 讨论(0)
  • 2020-11-22 06:21

    I know this is an old issue, but had the same problem and none of the above solution really did the trick for the problem I was facing. I have created a dictionary which maps the file name with the LastWriteTime. So if the file is not in the dictionary will go ahead with the process other wise check to see when was the last modified time and if is different from what it is in the dictionary run the code.

        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
                    }
                }
    
    0 讨论(0)
  • 2020-11-22 06:24

    This code worked for me.

            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);
        }
    
    0 讨论(0)
  • 2020-11-22 06:24

    Event if not asked, it is a shame there are no ready solution samples for F#. To fix this here is my recipe, just because I can and F# is a wonderful .NET language.

    Duplicated events are filtered out using FSharp.Control.Reactive package, which is just a F# wrapper for reactive extensions. All that can be targeted to full framework or netstandard2.0:

    let createWatcher path filter () =
        new FileSystemWatcher(
            Path = path,
            Filter = filter,
            EnableRaisingEvents = true,
            SynchronizingObject = null // not needed for console applications
        )
    
    let createSources (fsWatcher: FileSystemWatcher) =
        // use here needed events only. 
        // convert `Error` and `Renamed` events to be merded
        [| fsWatcher.Changed :> IObservable<_>
           fsWatcher.Deleted :> IObservable<_>
           fsWatcher.Created :> IObservable<_>
           //fsWatcher.Renamed |> Observable.map renamedToNeeded
           //fsWatcher.Error   |> Observable.map errorToNeeded
        |] |> Observable.mergeArray
    
    let handle (e: FileSystemEventArgs) =
        printfn "handle %A event '%s' '%s' " e.ChangeType e.Name e.FullPath 
    
    let watch path filter throttleTime =
        // disposes watcher if observer subscription is disposed
        Observable.using (createWatcher path filter) createSources
        // filter out multiple equal events
        |> Observable.distinctUntilChanged
        // filter out multiple Changed
        |> Observable.throttle throttleTime
        |> Observable.subscribe handle
    
    [<EntryPoint>]
    let main _args =
        let path = @"C:\Temp\WatchDir"
        let filter = "*.zip"
        let throttleTime = TimeSpan.FromSeconds 10.
        use _subscription = watch path filter throttleTime
        System.Console.ReadKey() |> ignore
        0 // return an integer exit code
    
    0 讨论(0)
  • 2020-11-22 06:24

    Try this!

    string temp="";
    
    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)
    {
       .......
    if(temp=="")
    {
       //do thing you want.
       temp = e.name //name of text file.
    }else if(temp !="" && temp != e.name)
    {
       //do thing you want.
       temp = e.name //name of text file.
    }else
    {
      //second fire ignored.
    }
    
    }
    
    0 讨论(0)
提交回复
热议问题