1. Technology

Write Programs That Run When a File is Added, Changed, or Deleted

It's easy with the .NET FileSystemWatcher component!


A reader needed a program that would "watch a folder for a specific file." If the file is added to the folder, some processing needs to be done before the program starts waiting for the file to appear again.

This is something that systems often need, but it used to be difficult to program. Back in the early days of DOS, a program like this was called a "TSR" (for "Terminate and Stay Resident") program and had to be coded in C++ or Assembler. You can still buy third party software that does this because it has been generally considered to be a complex programming job. (See, for example, DataMystic's Filewatcher.) SourceForge has a whole section of FileWatcher utilities.

But now it's easy to code this in Visual Basic because .NET provides a component called FileSystemWatcher that uses an operating system API (the same one that Windows Explorer uses) to monitor a whole list of file changes. It's also efficient because FileSystemWatcher isn't a polling program. It's event based. It monitors the SMB message queue and only consumes CPU cycles when it's notified that something needs to be done. For example, the statement ...

 Dim changeStruct As IO.WaitForChangedResult _
    = WatchForEnd.WaitForChanged(IO.WatcherChangeTypes.All) 

... will return a structure that contains the change that occurred such as Name, OldName, and TimedOut. FileSystemWatcher also features a WaitForChanged method that delays the initiation of monitoring until a specific event occurs. For example, if an application should ignore any changes until a 'start' time.

To answer my reader's question, I coded a quick example that checks for the existance of a file named "job.flg". To fit the needs my reader wrote about more closely, the example runs another program I called job.exe, deletes job.flg, and then goes back to watching. To detect when job.exe finishes executing, the program waits for a FormClosed event. I've also used my Temp directory for testing, but any directory should work.

To try out my FileWatcher program, I had to simulate job.exe actually doing something. This code works along with FileWatcher to test it. (Parameters are not shown to make the code easier to read.)

 Private Sub Form1_FormClosed( ...
    My.Computer.FileSystem.CopyFile( _
       "jobfolder/job.end", _
 End Sub 

In a real system, FileWatcher might be called by a batch file ("job.bat") which could create the "job.end" file. Or more sophisticated methods, such as a callback to the FileWatcher program, could be used.

Step 1 - Add two FileSystemWatcher components to a Windows Forms application.

Adding FileSystemWatcher to a standard Windows Forms application is a good way to write the code. The window interface can let you change user options, such as the type of file monitored, or even suspend file monitoring. The reader wanted to detect both when job.flg is added and when job.exe finishes running so two components - one to watch for each file - were used.

Step 2 - Add the properties and code.

The form Load event is used below to show what's happening rather than updating property values during design.

 Private Sub Form1_Load( ...
    programStatus.Text = "Watching for job.flg file"
    Watcher.Filter = "job.flg"
    Watcher.Path = "C:\Users\TEMP"
    WatchForEnd.Filter = "job.end"
    WatchForEnd.Path = "C:\Users\TEMP"
 End Sub
 Private Sub Watcher_Created( ...
    programStatus.Text = "Running job.exe"
 End Sub
 Private Sub WatchForEnd_Created( ...
    programStatus.Text = "Watching for job.flg file"
 End Sub 

This works pretty well. In fact, it can even start multiple copies of the "job.exe" program (See the illustration). But it still needs work. For one thing, in some circumstances, it will crash because two programs are trying to access the same file (a "locked" file). So, depending on your needs, you might want to consider reading flag values in a configuration file or even setting values in the registry rather than using files as flags as shown here. (I did it this way to match the specifications of the reader.)

Click Here to display the illustration
Click the Back button on your browser to return

You can also programm FileSystemWatcher as a Windows Service rather than as a Windows Form application. Unfortunately, the template to program a Windows Service is only available in Visual Studio Professional and above. <b>What to Watch Out For</b>

Some of the possible FileSystemWatcher applications could involve the processing of a huge number of events. For example, a computer that is an FTP server receiving files from the Internet could process many thousands. FileSystemWatcher stores changes in a buffer and then passes them to the Windows API to give it the capability to handle quite a few events. But any buffer will eventually run out of space and overflow. If this happnes, FileSystemWatcher will only provide a "blanket" notification and will raise an exception, so you should always use a Try-Catch structure with FileSystemWatcher. You can change the size of the buffer with the InternalBufferSize property. The default is 8K (8192) which will handle about 160 file events. To keep the processing as efficient as possible, it's common to hand off any processing that an event does require to a different thread. Also, make sure that filters are used to screen out irrelevant events.

If a file is locked ... which can happen for a variety of reasons including bugs ... you only have a choice of not processing that file, or coding a loop that does poll the file and wait for it to become unlocked again. Don't code the loop to poll indefinitely or your program will crash because it accumulates too many unresolvable locked files.

And, of course, FileSystemWatcher won't work on read only media like CDs or DVDs or removable media.

  1. About.com
  2. Technology
  3. Visual Basic
  4. Quick Tips
  5. FileSystemWatcher Programs With VB.NET

©2014 About.com. All rights reserved.