12.11 Monitoring File and Directory Changes

 <  Day Day Up  >  

You want to be notified whenever a file, directory, or collection of files and directories change.


Technique

The FileSystemWatcher class is designed to watch a group of files and directories and fire appropriate events based on the actions currently occurring to those groups. Using a FileSystemWatcher object is a four-step process. The first step is to create an instance of the FileSystemWatcher . You can use a default constructor when you create it, a single string denoting the directory path to watch, or an additional string beyond that specifying a filter, which is used to monitor individual file changes within a directory.

You can configure the FileSystemWatcher by setting certain properties. The first and most important is the Path property. Without this value, the FileSystemWatcher does not know the location to begin monitoring. Note also that it should be a path to a directory and not a path to a file. If you want to watch an individual file, then you want to set the Filter property. You use the Filter property to narrow down the list of files to watch and you can specify it using wildcards. For example, if you just want notification on changes occurring to text files, then the filter property is *.txt .

The IncludeSubdirectories property does just as its name implies. If any of the files change in the directory being monitored , or in any subdirectory underneath that directory, then the appropriate event is fired . If IncludeSubdirectories is false , then only the directory specified in the Path property is monitored.

Last but definitely not least is the event-handling mechanism. FileSystemWatcher fires off four different events based on the changes occurring to the monitored directory. One of these events is the Changed event. This event uses information in the NotifyFilters property to fire events whenever a certain change to a file or directory occurs. These changes can include attribute changes, last write time changes, and size changes, among others. To specify multiple NotifyFilters , logically OR ( ) each value from the NotifyFilters enumeration that you want to include:

 
 fileWatcher.NotifyFilter = NotifyFilters.LastAccess  NotifyFilters.LastWrite       NotifyFilters.FileName  NotifyFilters.DirectoryName; 

The other available events that are fired from a FileSystemWatcher object include Deleted , Renamed , and Created . The delegates for each of these events contain the obligatory object representing the sender and a FileSystemEventArgs . However, the Renamed event uses a RenamedEventArgs , which adds information about what the file was named before the renaming took place. In Listing 12.2, you can see a Windows Form application that allows you to specify a path, pattern, and whether to include subdirectories. When the Go button is clicked, the FileSystemWatcher is called into action by setting its EnableRaisingEvents property to true . Then, the appropriate events are fired and handled within their corresponding delegates. Take note that the wizard-generated code for the Windows Forms controls is left out for brevity, but the important FileSystemWatcher code is there.

Listing 12.2 The FileSystemWatcher Application
 using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using System.IO; namespace _11_FileWatcher {     public class Form1 : System.Windows.Forms.Form     {         private System.Windows.Forms.GroupBox groupBox1;         private System.Windows.Forms.TextBox tbPath;         private System.Windows.Forms.Button btnBrowse;         private System.Windows.Forms.TextBox tbActivity;         private System.Windows.Forms.GroupBox Activity;         private System.Windows.Forms.Button btnGo;         private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1;         private System.IO.FileSystemWatcher fileSystemWatcher1;         private System.Windows.Forms.CheckBox cbIncludeSubdirs;         private System.Windows.Forms.TextBox tbPattern;         private System.Windows.Forms.Label label1;         private System.ComponentModel.Container components = null;         public Form1()         {             InitializeComponent();         }         protected override void Dispose( bool disposing )         {             if( disposing )             {                 if (components != null)                 {                     components.Dispose();                 }             }             base.Dispose( disposing );         }         private void InitializeComponent()         {             // fileSystemWatcher1             this.fileSystemWatcher1 = new System.IO.FileSystemWatcher();             this.fileSystemWatcher1.Deleted += new                 System.IO.FileSystemEventHandler(                 this.fileSystemWatcher1_Deleted);             this.fileSystemWatcher1.Renamed += new                 System.IO.RenamedEventHandler(                 this.fileSystemWatcher1_Renamed);             this.fileSystemWatcher1.Changed += new                 System.IO.FileSystemEventHandler(                 this.fileSystemWatcher1_Changed);             this.fileSystemWatcher1.Created += new                 System.IO.FileSystemEventHandler(                 this.fileSystemWatcher1_Created);             // remaining windows forms control code removed         }         [STAThread]         static void Main()         {             Application.Run(new Form1());         }         private void btnBrowse_Click(object sender, System.EventArgs e)         {             // choose which folder to monitor             if( folderBrowserDialog1.ShowDialog() == DialogResult.OK )                 tbPath.Text = folderBrowserDialog1.SelectedPath;         }         private void btnGo_Click(object sender, System.EventArgs e)         {             if( btnGo.Text == "Stop" )             {                 // stop monitoring                 fileSystemWatcher1.EnableRaisingEvents = false;                 // change button text back to Go                 btnGo.Text = "Go";             }             else             {                 // make sure path exists                 if( Directory.Exists( tbPath.Text ) == false )                 {                     tbActivity.Text = "Directory \"" + tbPath.Text +                         "\" does not exist.";                     return;                 }                 // set filesystemwatcher properties                 fileSystemWatcher1.Path = tbPath.Text;                 fileSystemWatcher1.Filter = tbPattern.Text;                 fileSystemWatcher1.IncludeSubdirectories =                     cbIncludeSubdirs.Checked;                 // start monitoring                 fileSystemWatcher1.EnableRaisingEvents = true;                 btnGo.Text = "Stop";             }         }         private void fileSystemWatcher1_Changed(object sender,             System.IO.FileSystemEventArgs e)         {             tbActivity.Text += "\r\nChanged: " + e.FullPath;         }         private void fileSystemWatcher1_Created(object sender,             System.IO.FileSystemEventArgs e)         {             tbActivity.Text += "\r\nCreated: " + e.FullPath;         }         private void fileSystemWatcher1_Deleted(object sender,             System.IO.FileSystemEventArgs e)         {             tbActivity.Text += "\r\nDeleted: " + e.FullPath;         }         private void fileSystemWatcher1_Renamed(object sender,             System.IO.RenamedEventArgs e)         {             tbActivity.Text += "\r\nRenamed from " + e.OldFullPath +                 " to " + e.FullPath;         }     } } 

Comments

File-change notification is nothing new to the Windows world. The FileSystemWatcher component is a wrapper around the WIN32 API methods FindFirstChangeNotification and FindNextChangeNotification . If you read the documentation on these methods, you will note many similarities between them and the equivalent FileSystemWatcher class in the .NET framework.

The FileSystemWatcher class uses an internal buffer to store the various notifications as they are received from the operating system. When the operating system begins any type of serious thrashing on the hard disk, the internal buffer within the FileSystemWatcher class will undoubtedly fill up. When an overflow of that buffer is finally reached, the FileSystemWatcher class throws an Error event that you can handle within your own class. If you find this event occurring often, you might want to take some of the following steps. First, setting the IncludeSubdirectories property to true can have a large effect on the buffer size if the initial directory to monitor contains several files and subdirectories. If one of these subdirectories is the main Windows folder, that is definitely the case. Second, you might not need to monitor all the NotifyFilter types. For instance, if you simply want to know when a file is changed, then you can specify NotifyFilter.LastWrite . There should be no need to specify any additional filters because they will more than likely result in more than one notification being sent. Finally, you can change the internal buffer size of a FileSystemWatcher by setting the InternalBufferSize property. The default value is 8192, so you should set it to something larger. Additionally, the documentation also mentions that for best performance, the buffer size should be in multiples of 4KB. This suggestion means that you use values of 12288, 16384, and so on.

 <  Day Day Up  >  


Microsoft Visual C# .Net 2003
Microsoft Visual C *. NET 2003 development skills Daquan
ISBN: 7508427505
EAN: 2147483647
Year: 2003
Pages: 440

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net