FileSystemWatcher vs polling to watch for file changes

C#File IoFilesystemwatcherDistributed Filesystem

C# Problem Overview


I need to setup an application that watches for files being created in a directory, both locally or on a network drive.

Would the FileSystemWatcher or polling on a timer would be the best option. I have used both methods in the past, but not extensively.

What issues (performance, reliability etc.) are there with either method?

C# Solutions


Solution 1 - C#

I have seen the file system watcher fail in production and test environments. I now consider it a convenience, but I do not consider it reliable. My pattern has been to watch for changes with the files system watcher, but poll occasionally to catch missing file changes.

Edit: If you have a UI, you can also give your user the ability to "refresh" for changes instead of polling. I would combine this with a file system watcher.

Solution 2 - C#

The biggest problem I have had is missing files when the buffer gets full. Easy as pie to fix--just increase the buffer. Remember that it contains the file names and events, so increase it to the expected amount of files (trial and error). It does use memory that cannot be paged out, so it could force other processes to page if memory gets low.

Here is the MSDN article on buffer : FileSystemWatcher..::.InternalBufferSize Property

Per MSDN:

> Increasing buffer size is expensive, as it comes from non paged memory that cannot be swapped out to disk, so keep the buffer as small as possible. To avoid a buffer overflow, use the NotifyFilter and IncludeSubdirectories properties to filter out unwanted change notifications.

We use 16MB due to a large batch expected at one time. Works fine and never misses a file.

We also read all the files before beginning to process even one...get the file names safely cached away (in our case, into a database table) then process them.

For file locking issues I spawn a process which waits around for the file to be unlocked waiting one second, then two, then four, et cetera. We never poll. This has been in production without error for about two years.

Solution 3 - C#

The FileSystemWatcher may also miss changes during busy times, if the number of queued changes overflows the buffer provided. This is not a limitation of the .NET class per se, but of the underlying Win32 infrastructure. In our experience, the best way to minimize this problem is to dequeue the notifications as quickly as possible and deal with them on another thread.

As mentioned by @ChillTemp above, the watcher may not work on non-Windows shares. For example, it will not work at all on mounted Novell drives.

I agree that a good compromise is to do an occasional poll to pick up any missed changes.

Solution 4 - C#

Also note that file system watcher is not reliable on file shares. Particularly if the file share is hosted on a non-windows server. FSW should not be used for anything critical. Or should be used with an occasional poll to verify that it hasn't missed anything.

Solution 5 - C#

Personally, I've used the FileSystemWatcher on a production system, and it has worked fine. In the past 6 months, it hasn't had a single hiccup running 24x7. It is monitoring a single local folder (which is shared). We have a relatively small number of file operations that it has to handle (10 events fired per day). It's not something I've ever had to worry about. I'd use it again if I had to remake the decision.

Solution 6 - C#

I currently use the FileSystemWatcher on an XML file being updated on average every 100 milliseconds.

I have found that as long as the FileSystemWatcher is properly configured you should never have problems with local files.

I have no experience on remote file watching and non-Windows shares.

I would consider polling the file to be redundant and not worth the overhead unless you inherently distrust the FileSystemWatcher or have directly experienced the limitations everyone else here has listed (non-Windows shares, and remote file watching).

Solution 7 - C#

I have run into trouble using FileSystemWatcher on network shares. If you're in a pure Windows environment, it might not be an issue, but I was watching an NFS share and since NFS is stateless, there was never a notification when the file I was watching changed.

Solution 8 - C#

I'd go with polling.

Network issues cause the FileSystemWatcher to be unreliable (even when overloading the error event).

Solution 9 - C#

I had some big problems with FSW on network drives: Deleting a file always threw the error event, never the deleted event. I did not find a solution, so I now avoid the FSW and use polling.

Creation events on the other hand worked fine, so if you only need to watch for file creation, you can go for the FSW.

Also, I had no problems at all on local folders, no matter if shared or not.

Solution 10 - C#

Returning from the event method as quickly as possible, using another thread, solved the problem for me:

private void Watcher_Created(object sender, FileSystemEventArgs e)
{
	Task.Run(() => MySubmit(e.FullPath));
}

Solution 11 - C#

Using both FSW and polling is a waste of time and resources, in my opinion, and I am surprised that experienced developers suggest it. If you need to use polling to check for any "FSW misses", then you can, naturally, discard FSW altogether and use only polling.

I am, currently, trying to decide whether I will use FSW or polling for a project I develop. Reading the answers, it is obvious that there are cases where FSW covers the needs perfectly, while other times, you need polling. Unfortunately, no answer has actually dealt with the performance difference(if there is any), only with the "reliability" issues. Is there anyone that can answer that part of the question?

EDIT : nmclean's point for the validity of using both FSW and polling(you can read the discussion in the comments, if you are interested) appears to be a very rational explanation why there can be situations that using both an FSW and polling is efficient. Thank you for shedding light on that for me(and anyone else having the same opinion), nmclean.

Solution 12 - C#

Working solution for working with create event instead of change

Even for copy, cut, paste, move.

class Program
{        

        static void Main(string[] args)
        {
            string SourceFolderPath = "D:\\SourcePath";
            string DestinationFolderPath = "D:\\DestinationPath";
            FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
            FileSystemWatcher.Path = SourceFolderPath;
            FileSystemWatcher.IncludeSubdirectories = false;
            FileSystemWatcher.NotifyFilter = NotifyFilters.FileName;   // ON FILE NAME FILTER       
            FileSystemWatcher.Filter = "*.txt";         
             FileSystemWatcher.Created +=FileSystemWatcher_Created; // TRIGGERED ONLY FOR FILE GOT CREATED  BY COPY, CUT PASTE, MOVE  
            FileSystemWatcher.EnableRaisingEvents = true;
			
            Console.Read();
        }     

        static void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
        {           
                string SourceFolderPath = "D:\\SourcePath";
                string DestinationFolderPath = "D:\\DestinationPath";

                try
                {
					// DO SOMETING LIKE MOVE, COPY, ETC
                    File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
                }
                catch
                {
                }          
        }
}

Solution for this file watcher while file attribute change event using static storage

class Program
{
    static string IsSameFile = string.Empty;  // USE STATIC FOR TRACKING

    static void Main(string[] args)
    {
         string SourceFolderPath = "D:\\SourcePath";
        string DestinationFolderPath = "D:\\DestinationPath";
        FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
        FileSystemWatcher.Path = SourceFolderPath;
        FileSystemWatcher.IncludeSubdirectories = false;
        FileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;          
        FileSystemWatcher.Filter = "*.txt";         
        FileSystemWatcher.Changed += FileSystemWatcher_Changed;
        FileSystemWatcher.EnableRaisingEvents = true;
		
        Console.Read();
    }     

    static void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
    {
        if (e.Name == IsSameFile)  //SKIPS ON MULTIPLE TRIGGERS
        {
            return;
        }
        else
        {
            string SourceFolderPath = "D:\\SourcePath";
            string DestinationFolderPath = "D:\\DestinationPath";

            try
            {
				// DO SOMETING LIKE MOVE, COPY, ETC
                File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
            }
            catch
            {
            }
        }
        IsSameFile = e.Name;
    }
}
   

This is a workaround solution for this problem of multiple triggering event.

Solution 13 - C#

I would say use polling, especially in a TDD scenario, as it is much easier to mock/stub the presence of files or otherwise when the polling event is triggered than to rely on the more "uncontrolled" fsw event. + to that having worked on a number of apps which were plagued by fsw errors.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJon TackaburyView Question on Stackoverflow
Solution 1 - C#Jason JacksonView Answer on Stackoverflow
Solution 2 - C#NomixView Answer on Stackoverflow
Solution 3 - C#Brent RockwoodView Answer on Stackoverflow
Solution 4 - C#chilltempView Answer on Stackoverflow
Solution 5 - C#JimView Answer on Stackoverflow
Solution 6 - C#PersistenceOfVisionView Answer on Stackoverflow
Solution 7 - C#Jon NortonView Answer on Stackoverflow
Solution 8 - C#JonView Answer on Stackoverflow
Solution 9 - C#TrebView Answer on Stackoverflow
Solution 10 - C#spludlowView Answer on Stackoverflow
Solution 11 - C#ThunderGrView Answer on Stackoverflow
Solution 12 - C#Rahul UttarkarView Answer on Stackoverflow
Solution 13 - C#user2819502View Answer on Stackoverflow