Monitoring File System using FileSystemWatcher Class - Part 2

AuthorDate of SubmissionUser Level
Mokhtar B.11/26/2001Intermediate

Source Code: FSWatcherDesMA.zip 16.9 KB

Introduction

In Part 1open in new window, we have seen how to use FileSystemWatcher class. Today I' m giving an example to monitor your file system.

Application Overview

To show how FileSystemWatcher component tracks the specified directory, I have provided a simple example application, which shows status of your directory contents in the textbox whenever a change, is made. This application has six class files, all are inherited from the System.Windows.Forms class.

  • Properties.cs - to set Directory Path which is going to be watched.
  • MonitorFS.cs - Main class file for watching changes to a specified directory. Also allows us to create and drop files & directories.
  • CreateDir.cs - to create a new directory depending on security permissions.
  • CreateFile.cs - to create a new file depending on security permissions.
  • DeleteDir.cs - to delete a particular directory depending on security permissions.
  • DeleteFile.cs - to delete a particular file depending on security permissions.

User Interface

Setting Path for FileSystemWatcher Component

One very important task is to set the directory path, which is going to be watched. This can be done through the startup form. The following screenshots shows you how to do this:

img_13_gif

img_13_gif2

You can set the path in two ways either in standard direction notation ("d:\") or in Universal Naming Convention (UNC) format ("\\192.168.1.6\d\" or "\\mokhtar\d\").

To check whether the given path is valid or not, I am using here Exists method of Directory class. As Directory Class is static one no need to instantiated it.

Private string dirPath = txtPath.Text;
--
--
if (Directory.Exists(dirPath))
-
-
-

If directory exists, then the directory path will be set to myPath property, which will be used later while instantiating FileSystemWatcher Class.

private string mPath;
- -
- -
- -
//property for path
public string myPath
{
    get
    {
        return mPath;
    }
    set
    {
        mPath = value;
    }
}
- -
- -
- -
protected void btnSetPath_Click(object Sender, EventArgs e)
{
    ---
    this.myPath = dirPath;
    ---
}

Monitoring File System

To monitor FileSystem, first we have instantiate the FileSystemWatcher Class, then we have to set necessary properties. To instantitate and set the properties of the class use the following code:

public class MonitorFS:Form
{
    private FileSystemWatcher myWatcher;
    ---
    ---
    public MonitorFS(string myPath)
    {
        //Initializing directory path from properties.cs file
        DirPath = myPath;
        --
        ---
        myWatcher = new FileSystemWatcher(DirPath);
        myWatcher.EnableRaisingEvents = true;
        myWatcher.IncludeSubdirectories = true;
        --
        ---
        --
    }
}

Next, we have to create event handlers of types FileSystemEventHandler for Created, Changed and Deleted Events and RenamedEventHandler for Renamed Events. These event handlers will in turn call the appropriate procedure when an entry is written to the log.

Event Handlers of Type FileSystemEventHandler

myWatcher.Created += new FileSystemEventHandler(myWatcher_Created);
myWatcher.Changed += new FileSystemEventHandler(myWatcher_Changed);
myWatcher.Deleted += new FileSystemEventHandler(myWatcher_Deleted);

Event Handler of Type RenamedEventHandler

myWatcher.Renamed += new RenamedEventHandler(myWatcher_Renamed);

Procedure for Created Event

protected void myWatcher_Created(object sender, FileSystemEventArgs e)
{
    txtInfo.Text += "ChangeType :: " + e.ChangeType.ToString() + "\nFullPath ::" + e.FullPath.ToString() + "\n\n";
}

Procedure for Changed Event

protected void myWatcher_Changed(object sender, FileSystemEventArgs e)
{
    txtInfo.Text += "ChangeType :: " + e.ChangeType.ToString() + "\nFullPath ::" + e.FullPath.ToString() + "\n\n";
}

Procedure for Deleted Event

protected void myWatcher_Deleted(object sender, FileSystemEventArgs e)
{
    txtInfo.Text += "ChangeType :: " + e.ChangeType.ToString() + "\nFullPath ::" + e.FullPath.ToString() + "\n\n";
}

All the above three events have common argument i.e., the FileSystemEventArgs that provides the following properties.

PropertyDescription
ChangeTypeGets the type of directory event that occurred.
FullPathGets the fully-qualified path of the affected file or directory
NameGets the name of the affected file or directory.

Procedure for Renamed Event

protected void myWatcher_Renamed(object sender, RenamedEventArgs e)
{
    txtInfo.Text += "ChangeType :: " + e.ChangeType.ToString() + "\nFullPath ::" + e.FullPath.ToString() + "\nOld FileName :: "+ e.OldName.ToString() + "\n\n";
}

The RenamedEventArgs provides two more properties in addition to FileSystemEventArgs.

PropertyDescription
OldFullPathGets the previous fully-qualified path of the affected file or directory.
OldNameGets the old name of the affected file or directory.

You can monitor your File System in the following ways:

  • Outside the application through creating, dropping and renaming files & Directories.
  • From the application through creating and dropping files & directories.

Making Changes Outside the Application

Watching Changes on Local Directories

The following screenshot shows how FileSystemWatcher component watches changes when a directory is created under root directory of d drive of 192.168.1.6 local system. Two events are raised i.e., Created and Renamed when you create a directory from the outside of the application.

img_1

You can watch the changes when a word document is created as shows in the following screenshot. The events called when a new document is created are Created, Changed and Renamed.

img_2

Watching Changes on Network Directories

You can also watch changes for network directories. The following screenshot shows you how it monitors for network drive. Three events are raised i.e. Created (twice), Deleted and Renamed, when you create a directory on a network directory.

img_3

Making Changes within the Application

You can watch the changes from the Application straight away by creating and dropping files & directories by using Directory and File Classes

The following screenshot shows you how to a create directory.

img_4

The CreateDir Form uses CreateDir.cs file for creating a directory from the application.

public class CreateDir:Form
{
    --
    --
    public CreateDir()
    {
        ----
        ---
        //Event Handler for Calling btnAddDir
        procedure btnAddDir.Click += new EventHandler(btnAddDir_Click);
        ----
        ---
    }
    //Event for Creating Directory
    protected void btnAddDir_Click(object Sender, EventArgs e)
    {
        //Getting path from mypath property
        string dir = myPath + "\\" + txtDir.Text;
        if(txtDir.Text != "" )
        {
            //Checks for directory
            if (!Directory.Exists(dir))
            {
                try
                {
                    Directory.CreateDirectory(dir); this.Hide();
                }
                //Exception raises if security violated
                catch(Exception CrDir)
                {
                    MessageBox.Show(CrDir.Message,"Error Creating Directory", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    this.Hide();
                }
            }
            else
            {
                MessageBox.Show(dir + " Directory already Exists","Directory Creation Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                txtDir.Focus();
                SendKeys.Send("{HOME}+{END}");
            }
        }
        else
        {
            MessageBox.Show("Please Enter Directory Name","Directory Creation Error", MessageBoxButtons.OK, MessageBoxIcon.Information);
            txtDir.Focus();
        }
    }
}

After creation of directory, created event will be raised and you can see the effect in the following screenshot.

img_5

Likewise, other options available are Create New File, Delete File and Delete Directory. This allows you to watch the changes straight away from the application itself.

If you are not having appropriate permissions i.e. standard permissions for accessing files and directories, then errors will be raised through exception handling. In the following screenshot, I'm trying to access the network directory \\kareem\c\ and prone to the following errors.

img_6

Conclusion

Finally, I conclude that FileSystemWatcher class is so efficient to watch any kind of changes on a specified directory. Using this class, we can write different kind of applications such as mailing your admin as soon as your directory is tampered.

Happy NET Programming...


About the Author: He is working as ASP/VB Programmer at Adsoft Solutions Pvt. Ltd, Bangalore, India. His Skills include ASP, VB, MS-SQL Server, COM/DCOM, MTS, ADSI, MSMQ, XML, PHP and PERL. Presently, he is updating to .Net Technologies. You can reach him through mokhtaropen in new window.



Monitoring File System using FileSystemWatcher Class - Part 1open in new window

Mokhtar B Mokhtar B Dec 29, 2005

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

NameDescription
AttributesThe attributes of the file or folder.
CreationTimeThe time the file or folder was created.
DirectoryNameThe name of the directory.
FileNameThe name of the file.
LastAccessThe date the file or folder was last opened.
LastWriteThe date the file or folder last had anything written to it.
SecurityThe security settings of the file or folder.
SizeThe 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 NameDescription
AllThe creation, deletion, change, or renaming of a file or folder.
ChangedThe change of a file or folder. The types of changes include: changes to size, attributes, security settings, last write, and last access time.
CreatedThe creation of a file or folder.
DeletedThe deletion of a file or folder.
RenamedThe 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.

Contributors: FHL