[ Team LiB ] |
Recipe 11.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 also need to be notified of any of these actions for a group of files and/or directories. This can aid in alerting your application as to when a file, such as a log file, 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 following method, TestWatcher, 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: public void TestWatcher( ) { FileSystemWatcher fsw = new FileSystemWatcher( ); fsw.Path = @"c:\"; fsw.Filter = @"*.txt"; fsw.IncludeSubdirectories = true; fsw.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Attributes | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size | NotifyFilters.CreationTime| NotifyFilters.DirectoryName; fsw.Changed += new FileSystemEventHandler(OnChanged); fsw.Created += new FileSystemEventHandler(OnCreated); fsw.Deleted += new FileSystemEventHandler(OnDeleted); fsw.Renamed += new RenamedEventHandler(OnRenamed); fsw.Error += new ErrorEventHandler(OnError); fsw.EnableRaisingEvents = true; string file = @"c:\myfile.txt"; string newfile = @"c:\mynewfile.txt"; FileStream stream = File.Create(file); stream.Close( ); File.Move(file,newfile); File.Delete(newfile); fsw.Dispose( ); } The following code implements the event handlers to handle the events that are raised by the FileSystemWatcher object that was created and initialized in the TestWatcher method: public void OnChanged(object source, FileSystemEventArgs e) { Console.WriteLine("File " + e.FullPath + " --> " + e.ChangeType.ToString( )); } public void OnDeleted(object source, FileSystemEventArgs e) { Console.WriteLine("File " + e.FullPath + " --> " + e.ChangeType.ToString( )); } public void OnCreated(object source, FileSystemEventArgs e) { Console.WriteLine("File " + e.FullPath + " --> " + e.ChangeType.ToString( )); } public void OnRenamed(object source, RenamedEventArgs e) { Console.WriteLine("File " + e.OldFullPath + " (renamed to)--> " + e.FullPath); } public void OnError(object source, ErrorEventArgs e) { Console.WriteLine("Error " + e.ToString( )); } 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 Longhorn. 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 of the framework. 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 FileSystemWatcher class. After creating the FileSystemWatcher object, we can set its properties in order to focus our efforts in watching a filesystem. Table 11-10 examines the various properties that can be set on this object.
The NotifyFilters enumeration values in Table 11-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. To decrease the number of raised events further, you can set the IncludeSubdirectories property to false. You should note that adding a narrower filter to the Filter property to filter out more files does not affect the number of raised events this object receives. The Filter property is applied to the information already stored in the buffer, so this will not help if you are losing notifications due to the buffer overflows. If the NotifyFilter and IncludeSubdirectories properties cannot be modified, consider increasing the InternalBufferSize property. To estimate what size to increase this buffer to, Microsoft provides the following tips:
If possible, increase the InternalBufferSize as a last resort since this is an expensive operation due to the buffer space being 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, but you notice at the end of this listing that the text file is finally 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. |
[ Team LiB ] |