Monitoring the File Structure


Sometimes, an application must do more than just read and write files to the file system. Sometimes, it is important to know when files or directories are being modified. the .NET Framework has made it easy to create custom applications that do just that.

The class that helps you to do this is the FileSystemWatcher class. This class exposes several events that your application can catch. This enables your application to respond to file system events.

The basic procedure for using the FileSystemWatcher is simple. First you must set a handful of properties, which specify where to monitor, what to monitor, and when it should raise the event that your application will handle. Then you give it the addresses of your custom event handlers, so that it can call these when significant events occur. Then you turn it on and wait for the events.

The properties that must be set before a FileSystemWatcher object is enabled are shown in the following table.

Property

Description

Path

This must be set to the file location or directory to monitor.

NotifyFilter

This is a combination of NotifyFilters enumeration values that specify what to watch for within the monitored files. These represent properties of the file or folders being monitored. If any of the specified properties change, an event is raised. The possible enumeration values are: Attributes, CreationTime, DirectoryName, FileName, LastAccess, LastWrite, Security, Size. Note that these can be combined using the binary OR operator.

Filter

A filter on which files to monitor, for example *.txt.

Once these settings have been set, you must write event handlers for the four events, Changed, Created, Deleted, and Renamed. As you saw in Chapter 13, this is simply a matter of creating your own method and assigning it to the object's event. By assigning your own event handler to these methods, your method will be called when the event is fired. Each event will fire when a file or directory matching the Path, NotifyFilter, and Filter property is modified.

Once you have set the properties and the events, set the EnableRaisingEvents property to true to begin the monitoring. In the following Try It Out, you'll use FileSystemWatcher in a simple client application to keep tabs on a directory of your choice.

Try It Out – Monitoring the File System

image from book

Here's a more sophisticated example utilizing much of what you have learned in this chapter.

  1. Create a new Windows application called FileWatch in the directory C:\BegVCSharp\ Chapter22.

  2. Set the various form properties using those shown in the following table.

    Property

    Setting

    FormBorderStyle

    FixedDialog

    MaximizeBox

    False

    MinimizeBox

    False

    Size

    302, 160

    StartPosition

    CenterScreen

    Text

    File Monitor

  3. Using the properties from the preceding table, add the required controls to the form and set the appropriate properties.

    Control

    Name

    Location

    Size

    Text

    TextBox

    txtLocation

    8, 24

    184,20

    Button

    cmdBrowse

    208, 24

    64, 24

    Browse...

    Button

    cmdWatch

    88, 56

    80, 32

    Watch!

    Label

    lblWatch

    8, 104

    0, 0

    Ensure that you see the Enabled property of the cmdWatch Button to False, since you can't watch a file before one has been specified, and the AutoSize property of lblWatch to True so that you'll be able to see its contents. Also add an OpenFileDialog control to the form, set its Name to FileDialog, and its Filter to All Files|*.*. When you are finished, your form should look like Figure 22-12.

    image from book
    Figure 22-12

  4. Now that the form looks good, you can add some code to make it do some work. The first thing you need to do is add your usual using directive for the System.IO namespace to the existing list of using directives:

    #region Using directives     using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Windows.Forms; using System.IO;     #endregion
  5. Now you must add the FileSystemWatcher class to the Form1 class, as well as a delegate to facilitate changing the text of lblWatch from different threads. Add the following code to Form1.cs:

    namespace FileWatch {    partial class Form1 : Form    { //File System Watcher object. private FileSystemWatcher watcher; private delegate void UpdateWatchTextDelegate(string newText); 

  6. You need to add some code to the form constructor. Just after the InitializeComponent() method call add the following code. This code is needed to initialize the FileSystemWatcher object and associate the events to methods that you are going to create next:

    public Form1() {    InitializeComponent();     this.watcher = new System.IO.FileSystemWatcher(); this.watcher.Deleted += new System.IO.FileSystemEventHandler(this.OnDelete); this.watcher.Renamed += new System.IO.RenamedEventHandler(this.OnRenamed); this.watcher.Changed += new System.IO.FileSystemEventHandler(this.OnChanged); this.watcher.Created += new System.IO.FileSystemEventHandler(this.OnCreate); }
  7. Add the following five methods to the Form1 class. The first method will be used to update the text in lblWatch asynchronously from the threads that will run the event handlers for the FileSystemWatcher events, and the other methods are the event handlers themselves:

     // Utility method to update watch text. public void UpdateWatchText(string newText) { lblWatch.Text = newText; } // Define the event handlers. public void OnChanged(object source, FileSystemEventArgs e) { try { StreamWriter sw = new StreamWriter("C:/FileLogs/Log.txt", true); sw.WriteLine("File: {0} {1}", e.FullPath, e.ChangeType.ToString()); sw.Close(); this.BeginInvoke(new UpdateWatchTextDelegate(UpdateWatchText), "Wrote change event to log"); } catch (IOException) { this.BeginInvoke(new UpdateWatchTextDelegate(UpdateWatchText), "Error Writing to log"); } } public void OnRenamed(object source, RenamedEventArgs e) { try { StreamWriter sw = new StreamWriter("C:/FileLogs/Log.txt", true); sw.WriteLine("File renamed from {0} to {1}", e.OldName, e.FullPath); sw.Close(); this.BeginInvoke(new UpdateWatchTextDelegate(UpdateWatchText), "Wrote renamed event to log"); } catch (IOException) { this.BeginInvoke(new UpdateWatchTextDelegate(UpdateWatchText), "Error Writing to log"); } } public void OnDelete(object source, FileSystemEventArgs e) { try { StreamWriter sw = new StreamWriter("C:/FileLogs/Log.txt", true); sw.WriteLine("File: {0} Deleted", e.FullPath); sw.Close(); this.BeginInvoke(new UpdateWatchTextDelegate(UpdateWatchText), "Wrote delete event to log"); } catch (IOException) { this.BeginInvoke(new UpdateWatchTextDelegate(UpdateWatchText), "Error Writing to log"); } } public void OnCreate(object source, FileSystemEventArgs e) { try { StreamWriter sw = new StreamWriter("C:/FileLogs/Log.txt", true); sw.WriteLine("File: {0} Created", e.FullPath); sw.Close(); this.BeginInvoke(new UpdateWatchTextDelegate(UpdateWatchText), "Wrote create event to log"); } catch (IOException) { this.BeginInvoke(new UpdateWatchTextDelegate(UpdateWatchText), "Error Writing to log"); } } 

  8. You will now add the Click event handler for the Browse... button. The code in this event handler will open the Open File dialog, allowing the user to select a file to monitor. Double-click the Browse... button and enter the following code:

    private void cmdBrowse_Click(object sender, EventArgs e) { if (FileDialog.ShowDialog() != DialogResult.Cancel )  { txtLocation.Text = FileDialog.FileName; cmdWatch.Enabled = true; } }

    The ShowDialog() method returns a DialogResult enumeration value representing how the user exited the File Open dialog. The user could have clicked OK or hit the Cancel button. You need to check that the user did not click the Cancel button, so you compare the result from the method call to the DialogResult.Cancel enumeration value before saving the user's file selection to the TextBox. Finally, you set the Enabled property of the Watch button to true so that you can watch the file.

  9. Now for the last bit of code. Follow the same procedure as above with the Watch button. Add the following code to launch the FileSystemWatcher:

    private void cmdWatch_Click(object sender, EventArgs e) { watcher.Path =Path.GetDirectoryName(txtLocation.Text); watcher.Filter = Path.GetFileName(txtLocation.Text); watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.Size; lblWatch.Text = "Watching " + txtLocation.Text; // Begin watching. watcher.EnableRaisingEvents = true;  }
  10. You need to make sure the FileLogs directory exists for you to write data to. Add the following code to the Form1 constructor that will check to see if the directory exists, and create the directory if it does not already exist.

    public Form1()  {     ...     DirectoryInfo aDir = new DirectoryInfo(@"C:\\FileLogs"); if (!aDir.Exists) aDir.Create();  } 
  11. Create a directory called C:\TempWatch and a file in this directory called temp.txt.

  12. Build the project. If everything builds successfully click the Browse button and select C:\ TempWatch\temp.txt.

  13. Click the Watch button to begin monitoring the file. The only change you will see in your application is the label control showing the file is being watched.

  14. Using Windows Explorer navigate to C:\TempWatch. Open temp.txt in Notepad and add some text to the file. Save the file.

  15. Rename the file.

  16. You can now check the log file to see the changes. Navigate to the C:\FileLogs\Log.txt file and open it in Notepad. You should see a description of the changes to the file you selected to watch, shown in Figure 22-13.

    image from book Figure 22-13

How It Works

This application is fairly simple, but it demonstrates how the FileSystemWatcher works. Try playing with the string you put into the monitor text box. If you specify *.* in a directory it will monitor all changes in the directory.

Most of the code in the application is based around setting up the FileSystemWatcher object to watch the correct location:

watcher.Path =Path.GetDirectoryName(txtLocation.Text); watcher.Filter = Path.GetFileName(txtLocation.Text); watcher.NotifyFilter = NotifyFilters.LastWrite |    NotifyFilters.FileName | NotifyFilters.Size; lblWatch.Text = "Watching " + txtLocation.Text; // Begin watching. watcher.EnableRaisingEvents = true; 

The code first sets the path to the directory to monitor. This uses a new object you have not looked at yet: the System.IO.Path object. This is a static class, very much like the static File object. It exposes many static methods to manipulate and extract information out of file location strings. You first use it to extract the directory name the user typed in from the text box, using the GetDirectoryName() method.

The next line sets the filter for the object. This can be an actual file, in which case it would only monitor the file, or it could be something like *.txt, in which case it would monitor all the .txt files in the directory specified. Again, you use the Path static object to extract the information from the supplied file location.

The NotifyFilter is a combination of NotifyFilters enumeration values that specify what constitutes a change. In this example, you have said that if the last write timestamp, the filename, or the size of the file changes then your application will be notified of the change. After updating the UI, you set the EnableRaisingEvents property to true to begin monitoring.

But before this you have to create the object and set the event handlers:

this.watcher = new System.IO.FileSystemWatcher(); this.watcher.Deleted +=    new System.IO.FileSystemEventHandler(this.OnDelete); this.watcher.Renamed +=    new System.IO.RenamedEventHandler(this.OnRenamed); this.watcher.Changed +=    new System.IO.FileSystemEventHandler(this.OnChanged); this.watcher.Created +=    new System.IO.FileSystemEventHandler(this.OnCreate);

This is how you hook up the event handlers for the watcher object with the private methods you have created. Here, you will have event handlers for the event raised by the watcher object when a file is deleted, renamed, changed or created. In your own methods, you decide how to handle the actual event. Note that you are notified after the event takes place.

In the actual event handler methods, you simply write the event to a log file. Obviously, this could be a more sophisticated response, depending on your application. When a file is added to a directory you could move it somewhere else or read the contents and fire off a new process using the information. The possibilities are endless!

image from book




Beginning Visual C# 2005
Beginning Visual C#supAND#174;/sup 2005
ISBN: B000N7ETVG
EAN: N/A
Year: 2005
Pages: 278

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