Monitoring File System using FileSystemWatcher Class - Part 1


Abstract:

If any one is experimenting your important directory without your notice, then you may think of an application, which helps you to monitor the changes of your directory. Earlier, writing this kind of application is too difficult, but with .NET you can do it through a simple and flexible component i.e. FileSystemWatcher, which watches your directory for any change using .NET. In this article, I am  explaining you how to use FileSystemWatcher class in Part 1.  In part 2, a sample application, which helps you to monitor a specified directory.

Introduction:

FileSystemWatcher is a very powerful component, which allows us to connect to the directories and watch for specific changes within them, such as creation of new files, addition of subdirectories and renaming of files or subdirectories. This makes it possible to easily detect when certain files or directories are created, modified or deleted. It is one of the members of System.IO namespace.

The FileSystemWatcher component is designed to watch for changes within the directory, not to changes to the directory's attributes themselves. For example, if you are watching a directory called c:\Mydir, the component will monitor changes within the directory but not changes to the directory itself.

The component can watch files on a local computer, network drive or a remote machine. FileSystemWatcher only works on Windows NT 4.0 and Windows 2000. You cannot watch a remote Windows NT 4.0 computer from a Windows NT 4.0 Computer. But, you can watch a remote Win2000 and local WinNT 4.0 and vice versa. Also you can watch a remote Win2000 and Win2000.

Requirements:

For the code in this article you will need:

Windows NT 4.0 or Windows 2000
NET Framework Beta 2
A text editor, such as Notepad, Text pad or Visual Studio .NET Beta2.

Configuring FileSystemWatcher Class:

To configure an instance of the FileSystemWatcher component,

  • Create an instance of the FileSystemWatcher component.
  • Configure necessary properties and methods for the component.
  • Create Handlers for FileSystem Events.

Creating FileSystemWatcher Component Instances:

To create an instance of the FileSystemWatcher component use one of the following:

Example:

//Intializes a new instance of the FileSystemWatcher Class
FileSystemWatcher myWatcher = new FileSystemWatcher();
//Intializes a new instance with a Path property
FileSystemWatcher myWatcher = new FileSystemWatcher("c:\\");
//Intializes a new instance along with a Path and Filter properties
FileSystemWatcher myWatcher = new FileSystemWatcher("c:\\","*.txt");

The component will not watch the specified directory until the Path is set, and EnableRaisingEvents is true. If you are using Visual Studio.NET, the FileSystemWatcher class is readily available in the Toolbox under the Components Tab and you can directly drag and drop the FileSystemWatcher class and EnableRaisingEvents is true by default.

Properties:

There are several properties you set for your FileSystemWatcher component instances to determine how they behave.  These properties determine what directories and subdirectories the component instance will monitor and the exact occurrences within those directories that will raise events.
 

  • Path - Sets or Gets the Path of the directory to watch.
  • EnableRaisingEvents - Enable or disable the component.
  • Filter - Gets or sets the filter string, used to determine what files are monitored in a directory. Default value is (*.*)
  • IncludeSubdirectories - Enables or disables including subdirectories to be watched.
  • InternalBufferSize - Gets or sets the size of internal buffer. Default is 8K.
  • NotifyFilter - Gets or sets the type of changes to watch for.  

Specifying Directories to Watch:

To specify what directories to be watched, Path and IncludeSubdirectories properties are used.

The Path property indicates the fully qualified path of the root directory you want to watch.  This can be in standard directory notation(c:\directory) or in UNC format (\\server\directory).  

Example:

FileSystemWatcher myWatcher = new FileSystemWatcher();
MyWatcher.Path = "c:\\";

The IncludeSubdirectories property indicates whether subdirectories within the root directory should be monitored.  If the property is set to true, the component watches for the same changes in the subdirectories as it does in the main directory the component is watching.

Specifying the Changes to Watch:

Set Filter property to an empty string ("") to watch for changes in all files.  To watch a specific file, set the Filter property to the file name say "samp.txt". You can also watch for changes in a certain type of file. For example, to watch for changes in document files, set the Filter property to "*.doc".

FileSystemWatcher class does not ignore hidden files. Setting the Filter does not decrease what goes into the buffer.

By setting NotifyFilter property to one of the NotifyFilters values, you can track several types of changes such as changes in Attributes, the LastWrite date and time, or the Size of files or directories or when security access to a file or directory rights changes. These values are all part of the NotifyFilters enumeration. You can set multiple changes to watch for by using "|" operator.

NotifyFilters enumeration:

Name Description
Attributes The attributes of the file or folder.
CreationTime The time the file or folder was created.
DirectoryName The name of the directory.
FileName The name of the file.
LastAccess The date the file or folder was last opened.
LastWrite The date the file or folder last had anything written to it.
Security The security settings of the file or folder.
Size The size of the file or folder.

Example:

FileSystemWatcher myWatcher = new FileSystemWatcher();
myWatcher.Path = "c:\\";
myWatcher.Filter = "*.txt";
myWatcher.EnableRaisingEvents = true;
myWatcher.IncludeSubdirectories = false;
myWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;

Your FileSystemWatcher component has the potential to receive an enormous number of events, particularly if you have set it to watch a very high-traffic directory. This can cause problems, as the FileSystemWatcher component can only receive event notifications at a manageable rate. The system notifies the component of file changes, it stores those changes in a buffer the component creates and passes to the Win32 Application Programming Interfaces (APIs). If there are many changes in a short time, the buffer can overflow. This causes the component to lose track of changes in the directory, and it will only provide "blanket" notification and the component will raise an exception. Default size is 4KB, you can increase the buffer size using InternalBufferSize, but increasing the size of the buffer is expensive, as it comes from non-paged memory that cannot be swapped out to disk, so keep the buffer as small as possible. A 4 KB buffer can track changes on approximately 80 files in a directory. Each event takes up 16 bytes in the buffer, plus enough bytes to store the name of the file, in Unicode (2 bytes per character), that the event occurred on. You can use this information to approximate the buffer size you will need.

To avoid a buffer overflow, use the NotifyFilter and IncludeSubdirectories properties so you can filter out unwanted change notifications.

Methods:

In addition to using the FileSystemWatcher component to immediately monitor a specific directory, you can use the WaitForChanged method to wait until a specific event occurs and then continue with execution of the thread. For example, if you are working with a Web-based news application, you might create an admin portion of the site where users upload their news stories. You could use the WaitForChanged method to watch that directory until the last access date changes, and then begin processing the news directory for new articles.

You specify the type of change to watch for by setting the value of a WatcherChangeType enumeration. The possible values are as follows:

Member Name Description
All    The creation, deletion, change, or renaming of a file or folder.
Changed    The change of a file or folder. The types of changes include: changes to size, attributes, security settings, last write, and last access time.
Created  The creation of a file or folder.
Deleted The deletion of a file or folder.
Renamed The renaming of a file or folder.

WaitForChanged is a synchronous method that returns an object of type WaitForChangedResult. This class contain specific information on the type of change that occurred in the directory. You can access information such as Name, OldName, and TimedOut on this object to find out more about the change. TimeOut is the time (in milliseconds) to wait before timing out.

If you use it in a Windows Form application, the application would stop responding if the method was used on the UI thread instead of the worker thread.

The following code track for all the changes.

Example:

1)myWatcher.WaitForChanged(WatcherChangeType.All);
//wait for one second before timing out
2)myWatcher.WaitForChanged(WatcherChangeType.All,1000);

Creating Handler for FileSystem Events:

The FileSystemWatcher Component raises four events depending on the types of changes that occur in the directory it is watching. These events are

  • Created - raised whenever a directory or file is created.
  • Deleted - raised whenever a directory or file is deleted.
  • Renamed - raised whenever the name of a directory or file is changed.
  • Changed - raised whenever changes are made to the size, system attributes, last write time, last access time or NTFS security permissions of a directory or file.

To access these events, you have to define handlers that automatically call methods in your code when a change occurs. To create a handler, use the following code:

Example:

//Handler for Changed Event
myWatcher.Changed += new FileSystemHandler(myWatcher_Changed);
//Handler for Created Event
myWatcher.Created += new FileSystemHandler(myWatcher_Created);
//Handler for Deleted Event
myWatcher.Deleted += new FileSystemHandler(myWatcher_Deleted);
//Handler for Renamed Event
myWatcher.Renamed += new RenamedEventHandler(myWatcher_Renamed);

Although some common occurances, such as copying or moving a file, do not correspond directly to an event, these occurances do cause events to be raised. When you copy a file, the system raises a Created event in the directory to which the file was copied but does not raise any events in the original directory. When you move a file, the server raises two events: a Deleted event in the source directory, followed by a Created event in the target directory.

For example, you create two instances of FileSystemWatcher. FileSystemWatcher1 is set to watch "C:\My Documents", and FileSystemWatcher2 is set to watch "C:\Your Documents". Now, if you copy a file from "My Documents" into "Your Documents", a Created event will be raised by FileSystemWatcher2, but no event is raised for FileSystemWatcher1. Unlike copying, moving a file or directory would raise two events. From the previous example, if you moved a file from "My Documents" to "Your Documents", a Created event would be raised by FileSystemWatcher2 and a Deleted event would be raised by FileSystemWatcher1.

Happy .NET Programming!!


Similar Articles