Click here to Skip to main content
15,031,208 members
Articles / Programming Languages / Markdown
Posted 7 Dec 2017


53 bookmarked

A Robust Solution for FileSystemWatcher Firing Events Multiple Times

Rate me:
Please Sign up or sign in to vote.
4.93/5 (20 votes)
18 Sep 2018CPOL2 min read
This is a robust solution for FileSystemWatcher firing events multiple times

The Problem

FileSystemWatcher is a great little class to take the hassle out of monitoring activity in folders and files but, through no real fault of its own, it can behave unpredictably, firing multiple events for a single action.

Note that in some scenarios, like the example used below, the first event will be the start of the file writing and the second event will be the end, which, while not documented behaviour, is at least predictable. Try it with a very large file to see for yourself.

However, FileSystemWatcher cannot make any promises to behave predictably for all OS and application behaviours. See also, MSDN documentation:

Common file system operations might raise more than one event. For example, when a file is moved from one directory to another, several OnChanged and some OnCreated and OnDeleted events might be raised. Moving a file is a complex operation that consists of multiple simple operations, therefore raising multiple events. Likewise, some applications (for example, antivirus software) might cause additional file system events that are detected by FileSystemWatcher.

Example: Recreating Edit a File in Notepad Firing 2 Events

As stated above, we know that 2 events from this action would mark the start and end of a write, meaning we could just focus on the second, if we had full confidence, this would be the consistent behaviour. For the purposes of this article, it makes for a convenient example to recreate.

If you edited a text file in c:\temp, you would get 2 events firing.

class ExampleAttributesChangedFiringTwice
        public ExampleAttributesChangedFiringTwice(string demoFolderPath)
            var watcher = new FileSystemWatcher()
                Path = demoFolderPath,
                NotifyFilter = NotifyFilters.LastWrite,
                Filter = "*.txt"

            watcher.Changed += OnChanged;
            watcher.EnableRaisingEvents = true;

        private static void OnChanged(object source, FileSystemEventArgs e)
            // This will fire twice if I edit a file in Notepad

Complete Console applications for both are available on Github.

A Robust Solution

Good use of NotifyFilters (see my post on how to select NotifyFilters) can help but there are still plenty of scenarios, like those above, where additional events will still get through for a file system event.

I worked on a nice little idea with a colleague, Ross Sandford, utilising MemoryCache as a buffer to ‘throttle’ additional events.

  1. A file event (changed in the example below) is triggered
  2. The event is handled by OnChanged. But instead of completing the desired action, it stores the event in MemoryCache with a 1 second expiration and a CacheItemPolicy callback setup to execute on expiration.
  3. When it expires, the callback OnRemovedFromCache completes the behaviour intended for that file event.

Note that I use AddOrGetExisting as a simple way to block any additional events firing within the cache period being added to the cache.

class BlockAndDelayExample
    private readonly MemoryCache _memCache;
    private readonly CacheItemPolicy _cacheItemPolicy;
    private const int CacheTimeMilliseconds = 1000;

    public BlockAndDelayExample(string demoFolderPath)
        _memCache = MemoryCache.Default;

        var watcher = new FileSystemWatcher()
            Path = demoFolderPath,
            NotifyFilter = NotifyFilters.LastWrite,
            Filter = "*.txt"

        _cacheItemPolicy = new CacheItemPolicy()
            RemovedCallback = OnRemovedFromCache

        watcher.Changed += OnChanged;
        watcher.EnableRaisingEvents = true;

    // Add file event to cache for CacheTimeMilliseconds
    private void OnChanged(object source, FileSystemEventArgs e)
        _cacheItemPolicy.AbsoluteExpiration =

        // Only add if it is not there already (swallow others)
        _memCache.AddOrGetExisting(e.Name, e, _cacheItemPolicy);

    // Handle cache item expiring
    private void OnRemovedFromCache(CacheEntryRemovedArguments args)
        if (args.RemovedReason != CacheEntryRemovedReason.Expired) return;

        // Now actually handle file event
        var e = (FileSystemEventArgs) args.CacheItem.Value;

If you’re looking to handle multiple, different, events from a single/unique file, such as Created with Changed, then you could key the cache on the file name and event named, concatenated.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer (Senior)
United Kingdom United Kingdom
Ben is the Technical Lead for C# .NET at a and .NET Foundation foundation member. He previously worked for over 8 years as a school teacher, teaching programming and Computer Science. He enjoys making complex topics accessible and practical for busy developers.

Comments and Discussions

Questiongood job Pin
Alen Toma30-Sep-18 9:01
MemberAlen Toma30-Sep-18 9:01 
QuestionRx is a good fit here Pin
Sacha Barber20-Sep-18 1:32
mvaSacha Barber20-Sep-18 1:32 
AnswerRe: Rx is a good fit here Pin
Reader Man San20-Sep-18 6:29
professionalReader Man San20-Sep-18 6:29 
AnswerRe: Rx is a good fit here Pin
pkfox1-Oct-18 4:07
professionalpkfox1-Oct-18 4:07 
GeneralTimely and Informative Pin
stixoffire19-Sep-18 17:06
Memberstixoffire19-Sep-18 17:06 
GeneralMy vote of 5 Pin
stixoffire19-Sep-18 17:03
Memberstixoffire19-Sep-18 17:03 
QuestionFileSystemWatcher is flaky Pin
obermd19-Sep-18 16:04
Memberobermd19-Sep-18 16:04 
While a really useful class, I find the dotNet wrappers for the underlying Win32 FileSystemWatcher to be flaky at best. Not only can it fire multiple times for the same action, it will also error out when file system activity causes too many events in too short of a time. My solution to the former is to not assume the event is accurate and to double-check the actual event conditions. For the latter issue I catch the FSW errors and increase the size of the buffers before reinitializing the FSW object and then I immediately call the event handler to check for the status I'm watching for - the error always occurs in lieu of the actual event.

QuestionMemoryCache reaction Pin
Nikolai Orekhov19-Sep-18 7:24
MemberNikolai Orekhov19-Sep-18 7:24 
GeneralMy vote of 5 Pin
BillWoodruff18-Sep-18 21:32
mveBillWoodruff18-Sep-18 21:32 
GeneralMy vote of 5 Pin
David Pierson10-Dec-17 19:32
MemberDavid Pierson10-Dec-17 19:32 
GeneralMy vote of 5 Pin
tbayart8-Dec-17 4:31
professionaltbayart8-Dec-17 4:31 
GeneralMy vote of 5 Pin
LightTempler7-Dec-17 12:22
MemberLightTempler7-Dec-17 12:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.