You need to be notified when a particular event occurs in the filesystem, such as the renaming of a particular file or directory, the increasing or decreasing of the size of a file, the user deleting a file or directory, the creation of a file or directory, or even the changing of a file or directory’s attribute(s). However, this notification must occur synchronously. In other words, the application cannot continue unless a specific action occurs to a file or directory.
The WaitForChanged
method of the FileSystemWatcher
class can be
called to wait synchronously for an event notification. This is
illustrated in the following method, which waits for an
action—more specifically, the action of creating the
Backup.zip
file somewhere on the
C:
drive—to be performed before
proceeding on to the next line of code, which is the
WriteLine
statement. Finally, we ask the
ThreadPool
to use a thread to go create the file
in question using the PauseAndCreateFile
method,
so that the FileSystemWatcher
can detect the file
creation:
public void WaitForZipCreation(string path, string fileName) { FileSystemWatcher fsw = null; try { fsw = new FileSystemWatcher( ); string [] data = new string[] {path,fileName}; fsw.Path = path; fsw.Filter = fileName; fsw.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; // Run the code to generate the file we are looking for // Normally you wouldn't do this as another source is creating // this file if(ThreadPool.QueueUserWorkItem(new WaitCallback(PauseAndCreateFile), data)) { // block waiting for change WaitForChangedResult result = fsw.WaitForChanged(WatcherChangeTypes.Created); Console.WriteLine("{0} created at {1}.",result.Name,path); } } catch(Exception e) { Console.WriteLine(e.ToString( )); } // clean it up File.Delete(fileName); if(fsw != null) fsw.Dispose( ); }
The code for PauseAndCreateFile
is listed here. It
is in the form of a WaitCallback
to be used as an
argument to QueueUserWorkItem
on the
Thread
class. QueueUserWorkItem
will run PauseAndCreateFile
on a thread from the
.NET thread pool:
void PauseAndCreateFile(Object stateInfo) { try { string[] data = (string[])stateInfo; // wait a sec... Thread.Sleep(1000); // create a file in the temp directory string path = data[0]; string file = path + data[1]; Console.WriteLine("Creating {0} in PauseAndCreateFile...",file); FileStream fileStream = File.Create(file); fileStream.Close( ); } catch(Exception e) { Console.WriteLine(e.ToString( )); } }
The WaitForChanged
method returns a WaitForChangedResult
structure
that contains the properties listed in Table 11-12.
Table 11-12. WaitForChangedResult properties
Property |
Description |
---|---|
ChangeType |
Lists the type of change that occurred. This change is returned as a
|
Name |
Holds the name of the file or directory that was changed. If the file
or directory was renamed, this property returns the changed name. Its
value is set to |
OldName |
The original name of the modified file or directory. If this file or
directory was not renamed, this property will return the same value
as the Name property. Its value is set to |
TimedOut |
Holds a Boolean indicating whether the
|
Now, you can certainly add a timeout to the
WaitForChanged
call to prevent you from hanging
forever on the WaitForChanged
call, but that is
more of a recovery option than actually performing the action you
want, which is to see a file change. This mechanism could be set up
in a loop to check periodically whether you should continue to
monitor for this file change (user could hit
“cancel” on your application in
another UI thread, for example).