This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Input / Output
.NET 1.1+

Detecting File Changes with FileSystemWatcher

If you are developing a Windows Explorer-style application or integrating with a legacy or third-party system that can only provide information via files, you may need to monitor the files within a folder. The FileSystemWatcher class permits this.

Buffer Size and the Error Event

The FileSystemWatcher class works by capturing all of the relevant file and older changes and placing them into a buffer. This is then processed one change at a time until all of the notifications have been dealt with and the buffer is empty. By default, the internal buffer has a size of eight kilobytes (8192 bytes). Each event can take up to sixteen bytes of the buffer for its data, not including the file name. This means that when there are a lot of changes in a short period of time, the buffer can quickly become overloaded and notifications can be lost.

One way to manage the buffer size problem is to change the maximum size that is permitted. If you know that your program is likely to process large numbers of file changes in a short period, you can change the value in the InternalBufferSize property. This property allows the size of the buffer to be specified as a number of bytes. Care should be taken as the buffer is held in memory that cannot be swapped to disk so this memory becomes unavailable to other programs. The size selected should be a multiple of 4096 to give the best performance.

Each time the buffer size limit is reached, the FileSystemWatcher object raises an Error event. This event allows you to identify that there has been a change but the details of the file or folder modified will not be available. Generally you would log this or create some kind of notification so that a recovery can be attempted.

To capture the Error event in the sample program, add the following line to the end of the form's constructor:

_watcher.Error += new ErrorEventHandler(LogBufferError);

To process this event, add the following method to the form's class:

void LogBufferError(object sender, ErrorEventArgs e)
    string log = string.Format("{0:G} | Buffer limit exceeded", DateTime.Now);

You can test this event by either reducing the buffer size of the FileSystemWatcher object or by manipulating large numbers of files within the monitored folder. (Creating copies of thousands of files can be used to overload the buffer.)

Filtering Monitored Files

When monitoring a folder for changes to a specific type of file or for files with certain names, a name filter can be applied to the FileSystemWatcher object. Once applied, events are only raised when the name of the file or folder that changed matches the filter condition. This has the potential benefit of reducing the buffer utilisation.

To apply a filter, the Filter property is set. If only a single file is to be monitored, the name of the file is specified. When a limited set of files or folders is required, wildcard characters can be included in the filter string. An asterisk symbol (*) is used to represent any number of characters and a question mark (?) is used to replace any single character. Some example filter strings are shown in the table below.

(Empty string)Any file or folder.
*.*Any file or folder
*.docAll files with a .doc extension.
monitor.*All files with a name of "monitor" and any extension
abc*.*All files that begin with "abc".
abc?.*All files with a four-letter filename that begins with abc and any extension.

To apply file name filtering in the demonstration application, we will link the FileFilterInput text box's contents to the Filter property of the FileSystemWatcher. This will be done by adding a line of code to the method that detects changes in the checkbox's status. Alter the method as follows:

private void MonitoringInput_CheckedChanged(object sender, EventArgs e)
    _watcher.Path = FolderInput.Text;
    _watcher.Filter = FileFilterInput.Text;
    _watcher.EnableRaisingEvents = MonitoringInput.Checked;

    FolderInput.Enabled = FileFilterInput.Enabled = !MonitoringInput.Checked;

After adding the filtering code, test the application using various filters.

Filtering Monitored Actions

A second type of filtering can be applied to limit the types of change that cause a notification event to be raised. This filtering is applied by setting the NotifyFilter property of the FileSystemWatcher. The property accepts a value based upon the NotifyFilters enumeration. This enumeration has a FlagsAttribute attribute so the various values may be combined using bitwise logical operators. This allows you to enable more than one type of notification whilst ignoring others. using this type of filtering reduces the number of notifications being sent to the internal buffer and the associated risk of the buffer being filled.

The following constant values and their linked notification types are defined in the enumeration:

Enumeration ConstantNotification Event For...
AttributesChanges to the file or folder attributes.
CreationTimeChanges to the creation time of a file or folder.
DirectoryNameChanges to the name of a folder.
FileNameChanges to the name of a file.
LastAccessChanges to the time that a file or folder was last opened.
LastWriteChanges to the time that a file or folder was last written to.
SecurityChanges to the file or folder security settings.
SizeChanges to the file or folder size.

These flags are included in the demo application and source code that can be downloaded using the link at the top of this article.

Monitoring Sub-Folders

The final property to be considered is IncludeSubdirectories. This Boolean value is used to indicate whether subfolders of the monitored directory should be monitored. When set to true, the entire hierarchy of folders beneath the specified path is observed and any changes cause events to be raised. This option should be used with care as it can lead to unexpectedly large numbers of notifications being added to the buffer, increasing the risk that it will be overfilled.

The property is included in the demo application and source code that can be downloaded using the link at the start of this article.

22 March 2008