This article is also available as a TechRepublic download, which includes a complete Visual Studio 2005 project file with example code.
There are many instances that require systems to perform certain tasks when files or directories are created or modified. One example of this is an import system that pulls flat files into a database. In this instance, a program must monitor a directory for newly created files. When a file is created, the program must pick up the file, parse it, and insert it into the database. Many times this type of functionality is accomplished by "polling" the directory and enumerating any new files that have been created since the last poll. With the introduction of the .NET Framework, Microsoft has provided developers with an alternative to constantly polling a directory for new files—the FileSystemWatcher object.
The FileSystemWatcher object does the work of monitoring a directory for you. When a file is created, updated, or deleted, the FileSystemWatcher fires an event to notify you that a change has occurred. This allows your program to know when a new file is available almost immediately after the file is created. Immediate notification of changes allows your system to work much more efficiently since you're not constantly polling the directory for changes, and there is no time lapse between scans of the directory.
The FileSystemWatcher basics
There are a few basic properties and events you need to familiarize yourself with before working with the FileSystemWatcher object. Undoubtedly, the most important property of this object is the "EnableRaisingEvents" property. This property determines whether or not the object will fire events when it receives a change notification. If EnableRaisingEvents is set to false, the object will not fire the change events. If it is set to true, the events will be fired. Below are several other important properties/events that you will use as you take advantage of FileSystemWatcher:
- Path — This property tells the FileSystemWatcher which path it needs to monitor. For example, if we set this property to "C:\Temp\", all changes in that directory would be monitored.
- IncludeSubDirectories — This property indicates whether or not the FileSystemWatcher should monitor subdirectories for changes.
- Filter — This property allows you to filter the changes for certain file types. For example, if we wanted to be notified only when TXT files are modified/created/deleted, we would set this property to "*.txt". This property is very handy when working with high-traffic or large directories.
- Changed — This event is fired when a file has been modified in the directory thatis being monitored. It is important to note that this event may be fired multiple times, even when only one change to the content of the file has occurred. This is due to other properties of the file changing as the file is saved.
- Created — This event is fired when a file is created in the directory that is being monitored. If you are planning to use this event to move the file that was created, you must write some error handling in your event handler that can handle situations where the file is currently in use by another process. The reason for this is that the Created event can be fired before the process that created the file has released the file. This will cause exceptions to be thrown if you have not prepared the code correctly.
- Deleted — This event is fired when a file is deleted in the directory that is being watched.
- Renamed — This event is fired when a file is renamed in the directory that is being watched.
Note: None of these events will be fired if you do not have EnableRaisingEvents set to true. If at any point your FileSystemWatcher does not seem to be working, check EnableRaisingEvents first to make sure it is set to true.
When an event handler is called by the FileSystemWatcher, it contains two arguments—an object called "sender", and a FileSystemEventArgs object called "e". The argument we're interested in is the FileSystemEventArgs argument. This object contains information about what caused the event to be fired. The following is available from the FileSystemEventArgs object:
- Name — This property contains the name of the file that caused the event to be fired. It DOES NOT contain that path to the file—only the file or directory name that caused the event to be fired.
- ChangeType — This is a type of WatcherChangeTypes and indicates which type of event was fired. Valid values are:
- FullPath — This contains the full path to the file that caused the event to fire. It includes the filename and the directory name.
Listing A is a simple example of how to use the FileSystemWatcher. In this example we are watching the "C:\Temp" directory for any *.TXT files that are created. This is probably the simplest use of the FileSystemWatcher.
//Create a new FileSystemWatcher.
FileSystemWatcher watcher = newFileSystemWatcher();
//Set the filter to only catch TXT files.
watcher.Filter = "*.txt";
//Subscribe to the Created event.
watcher.Created += new
//Set the path to C:\Temp\
watcher.Path = @"C:\Temp\";
//Enable the FileSystemWatcher events.
watcher.EnableRaisingEvents = true;
void watcher_FileCreated(object sender, FileSystemEventArgs e)
//A new .TXT file has been created in C:\Temp\
Console.WriteLine("A new *.txt file has been created!");
Other examples are shown in the sample project included in the download version of this article.
The uses of the FileSystemWatcher may not be obvious at first. Obviously, it will alert us that a file or directory has been modified, but in what situations would that information be necessary?
One situation where it could be used is in a system that allows clients to upload files to be processed. While this is obviously the age of Web services and SOA, many systems still work by being fed flat files to certain locations, whether those locations are an FTP server or a network share. I have used the FileSystemWatcher for this type of system, and while it's not flawless, it certainly has its advantages over polling the directories for new changes.
Another situation where it could be used is if you want to keep two files in sync with one another. You could use the FileSystemWatcher to monitor both file locations and fire a Changed event when one of them is updated. You could then copy the changes over to the other system/file.
If your system has any functionality that requires files or directories to be monitored, you should look closely at that component to see if the FileSystemWatcher could be of use. In my case, this object saves at least 10 seconds on every file that is sent to the system.