You 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.
To 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( )); }
Watching 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.
Table 11-10. Properties that can be set on the FileSystemWatcher object
Property name |
Description |
---|---|
|
A path to a directory in which to watch. The following are some examples of valid values for this property: @"C: emp" @"C:Program Files" @"C:Progra~1" @".... emp" @"\MyServer emp" @"." @"" Note that if a directory is specified, changes to it, such as
deleting it or changing its attributes, are not watched. Only changes
within the |
|
Set to |
|
Specifies a specific subset of files to watch. The following are some examples of valid values for this property: @"*.exe" // Watch only .exe files @"*" // Watch all files @"" // Watch all files @"a*" // Watch all files beginning with the letter 'a' @"test.d??" // Watch all files with the name "test" and having a three letter extension starting with the letter 'd' |
|
One or more |
|
When this property is set to |
|
The internal buffer size in bytes for this object. It is used to store information about the raised filesystem events. This buffer defaults in size to 8192 bytes. See additional information about this property next. |
Table 11-11. NotifyFilters enumeration value definitions
Enumeration name |
Description |
---|---|
|
Watches for changes to a file or directory’s attributes. |
|
Watches for changes to a file or directory’s creation time. |
|
Watches for changes to a directory’s name. |
|
Watches for changes to a file’s name. |
|
Watches for changes to a file or directory’s last-accessed property. |
|
Watches for changes to a file or directory’s last-written-to property. |
|
Watches for changes to a file or directory’s security settings. |
|
Watches for changes to a file or directory’s size. |
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:
A 4k byte buffer can keep track of changes for about 80 files in a directory.
Every event consumes 16 bytes of buffer space.
In addition to these 16 bytes, the filename is stored as Unicode characters.
If you are using Windows 2000, consider increasing/decreasing the buffer size by a multiple of 4k bytes. This is the same size as a default memory page.
If you do not know your operating system’s page
size, use the following code to increase the
FileSystemWatcher
’s buffer size:
FileSystemWatcher fsw = new FileSystemWatcher( );
fsw.InternalBufferSize *= Multiplier
;
where Multiplier
is an integer used to
increase the size of the buffer. This makes the most efficient use of
the buffer space.
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 settingsadministrator tuser.dat.log --> Changed File c:documents and settingsadministrator tuser.dat.log --> Changed File c:documents and settingsadministrator tuser.dat.log --> Changed File c:documents and settingsadministrator tuser.dat.log --> Changed File c:documents and settingsadministrator tuser.dat.log --> Changed File c:documents and settingsadministrator tuser.dat.log --> Changed File c:documents and settingsadministrator tuser.dat.log --> Changed File c:documents and settingsadministrator tuser.dat.log --> Changed File c:documents and settingsadministrator tuser.dat --> Changed File c:documents and settingsadministrator tuser.dat --> Changed File c:documents and settingsadministrator tuser.dat --> Changed File c:documents and settingsadministrator tuser.dat --> Changed File c:documents and settingsadministrator tuser.dat.log --> Changed File c:winntsystem32configsoftware.log --> Changed File c:winntsystem32configsoftware.log --> Changed File c:winntsystem32configsoftware.log --> Changed File c:winntsystem32configsoftware --> Changed File c:winntsystem32configsoftware --> Changed File c:winntsystem32configsoftware --> Changed File c:winntsystem32configsoftware --> Changed File c:winntsystem32configsoftware.log --> Changed File c:documents and settingsadministratordesktop ewdoc.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:winntsystem32 otepad.exe --> Changed File c:winntsystem32 otepad.exe --> Changed File c:documents and settingsadministrator ecent ewdoc.txt.lnk --> Deleted File c:documents and settingsadministrator ecent ewdoc.txt.lnk --> Created File c:documents and settingsadministrator ecent ewdoc.txt.lnk --> Changed File c:winntsystem32configsoftware.log --> Changed File c:winntsystem32shell32.dll --> Changed File c:winntsystem32shell32.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.