Recipe 12.23. Watching the Filesystem for Specific Changes to One or More Files or DirectoriesProblemYou want to be notified when a file and/or directory is created, modified, or deleted. In addition, you might need to be notified of any of these actions for a group of files and/or directories. This can aid in alerting your application when a file, such as a logfile, grows to a certain size, after which it must be truncated. SolutionTo be notified when an action takes place in the filesystem, you need to employ the FileSystemWatcher class. The TestWatcher method shown in Example 12-12 sets up a FileSystemWatcher object to watch the entire C:\ drive for any changes. The changes are limited to any file with the extension .txt. At the end of this method, the events are wired up for each one of the changes listed in the NotifyFilter property. Example 12-12. Using the FileSystemWatcher class
The following code implements the event handlers to handle the events raised by the FileSystemWatcher object, which we created and initialized in the TestWatcher method: public static void OnChanged(object source, FileSystemEventArgs e) { Console.WriteLine("File " + e.FullPath + " --> " + e.ChangeType); } public static void OnDeleted(object source, FileSystemEventArgs e) { Console.WriteLine("File " + e.FullPath + " --> " + e.ChangeType); } public static void OnCreated(object source, FileSystemEventArgs e) { Console.WriteLine("File " + e.FullPath + " --> " + e.ChangeType); } public static void OnRenamed(object source, RenamedEventArgs e) { Console.WriteLine("File " + e.OldFullPath + " (renamed to)--> " + e.FullPath); } public static void OnError(object source, ErrorEventArgs e) { Console.WriteLine("Error " + e.ToString( )); } The output of the TestWatcher method is shown here: File c:\myfile.txt --> Created File c:\myfile.txt --> Changed File c:\mynewfile.txt --> Created File c:\mynewfile.txt --> Changed File c:\myfile.txt --> Deleted DiscussionWatching for changes in the filesystem centers around the FileSystemWatcher class. This class can watch for filesystem changes on the local machine, a networked drive, and even a remote machine. The limitations of watching files on a remote machine are that the watching machine must be running versions of Windows starting from Windows NT 4.0 through 2000, XP, Server 2003, and Windows Vista. The one caveat for Windows NT 4.0 is that a Windows NT 4.0 machine cannot watch another remote Windows NT 4.0 machine. The FileSystemWatcher object cannot watch directories or files on a CD or DVD drive (including rewritables) in the current versions of the Framework. This limitation might be revisited in a future version. This object does watch files regardless of whether their hidden property is set. To start watching a filesystem, we need to create an instance of the FileSystem-Watcher class. After creating the FileSystemWatcher object, we can set its properties in order to focus our efforts in watching a filesystem. Table 12-10 examines the various properties that can be set on this object.
The NotifyFilters enumeration values in Table 12-11 determine which events the FileSystemWatcher object watches. For example, the OnChanged event can be raised when any of the following NotifyFilters enumeration values are passed to the NotifyFilter property: NotifyFilters.Attributes NotifyFilters.Size NotifyFilters.LastAccess NotifyFilters.LastWrite NotifyFilters.Security NotifyFilters.CreationTime
The OnRenamed event can be raised when any of the following NotifyFilters enumeration values are passed to the NotifyFilter property: NotifyFilters.DirectoryName NotifyFilters.FileName The OnCreated and OnDeleted events can be raised when any of the following NotifyFilters enumeration values are passed to the NotifyFilter property: NotifyFilters.DirectoryName NotifyFilters.FileName There are times when the FileSystemWatcher object cannot handle the number of raised events coming from the filesystem. In this case, the Error event is raised, informing you that the buffer has overflowed and specific events may have been lost. To reduce the likelihood of this problem, we can limit the number of raised events by minimizing the number of events watched for in the NotifyFilter property. Limiting the filter on the Filter property, however, will not affect the number of raised events. To decrease the number of raised events further, you can set the IncludeSubdirectories property to false. You might also consider increasing the InternalBufferSize property. To estimate what size to increase this buffer to, Microsoft provides the following tips:
You should increase the InternalBufferSize only as a last resort. This is an expensive operation, because the buffer space is created in nonpaged memory. Nonpaged memory is memory available to the process that will always be in physical memory. It is a limited resource and is shared across all processes on the machine, so it is possible to affect the operation of other processes using this pool if too much is requested. In many cases, a single action performed by the user produces many filesystem events. Creating a text file on the desktop yields the following changes: File c:\documents and settings\administrator\ntuser.dat.log --> Changed File c:\documents and settings\administrator\ntuser.dat.log --> Changed File c:\documents and settings\administrator\ntuser.dat.log --> Changed File c:\documents and settings\administrator\ntuser.dat.log --> Changed File c:\documents and settings\administrator\ntuser.dat.log --> Changed File c:\documents and settings\administrator\ntuser.dat.log --> Changed File c:\documents and settings\administrator\ntuser.dat.log --> Changed File c:\documents and settings\administrator\ntuser.dat.log --> Changed File c:\documents and settings\administrator\ntuser.dat --> Changed File c:\documents and settings\administrator\ntuser.dat --> Changed File c:\documents and settings\administrator\ntuser.dat --> Changed File c:\documents and settings\administrator\ntuser.dat --> Changed File c:\documents and settings\administrator\ntuser.dat.log --> Changed File c:\winnt\system32\config\software.log --> Changed File c:\winnt\system32\config\software.log --> Changed File c:\winnt\system32\config\software.log --> Changed File c:\winnt\system32\config\software --> Changed File c:\winnt\system32\config\software --> Changed File c:\winnt\system32\config\software --> Changed File c:\winnt\system32\config\software --> Changed File c:\winnt\system32\config\software.log --> Changed File c:\documents and settings\administrator\desktop\newdoc.txt Created Much of this work is simply registry access. Not until the end of this listing is the text file actually created. Another example of multiple filesystem events firing for a single action is when this newly created text file is opened by double-clicking on it. The following events are raised by this action: File c:\winnt\system32\notepad.exe --> Changed File c:\winnt\system32\notepad.exe --> Changed File c:\documents and settings\administrator\recent\newdoc.txt.lnk --> Deleted File c:\documents and settings\administrator\recent\newdoc.txt.lnk --> Created File c:\documents and settings\administrator\recent\newdoc.txt.lnk --> Changed File c:\winnt\system32\config\software.log --> Changed File c:\winnt\system32\shell32.dll --> Changed File c:\winnt\system32\shell32.dll --> Changed Of course, your results may vary, especially if another application accesses the registry or another file while the text file is being opened. Even more events may be raised if a background process or service, such as a virus checker, is accessing the filesystem. See AlsoSee the "FileSystemWatcher Class" and "NotifyFilters Enumeration" topics in the MSDN documentation. |