October 1st, 2007
A common behind-the-scenes operation is to watch for the arrival of new files in a folder. I’ve had several projects where I had to watch for files arriving via FTP or HTTP uploads and then move these files off the web server and process them elsewhere on the network. In this article, we’ll look at the basics of using the FileSystemWatcher class to monitor file activity.
Creating a FileSystemWatcher
FileSystemWatcher is a member of the System.IO namespace. Remember that you’ll either need to import this namespace or explicitly type it out to use this class. When you create a FileSystemWatcher object you can create it with no parameters, you can specify the path you want it to monitor or you can specify both the path and the filter you wish to use. Here are some examples:
Watcher = New FileSystemWatcher '. '..... '. Watcher = New FileSystemWatcher(WatchPath) '. '..... '. Watcher = New FileSystemWatcher(WatchPath, WatchFilter)
The path parameter/property can be any valid UNC file path so you can watch both local and networked drives. Make sure that your user has access right to any paths they will need to access. This is especially critical for Windows Service applications running under LOCAL SERVICE or NETWORK SERVICE built-in IDs. Remember these IDs will usually need to be give access to target folders by an administrator.
The filter parameter/property is used to determine which files will be watched. You can use standard wildcards to look for particular file types, for example “*.doc”, or for a specific file, for example “annual_report.xls”.
There are two filter properties in the FileSystemWatcher, one, as we mentioned above, to determine the file name(s) to watch for and NotifyFilter which says what kind of file system events to watch. By default, the NotifyFilter property is set to watch for a file to be written or for the file or directory name to be changed. You can also check for the file size, file security, or attributes changing. This property is a bitwise mask so you’ll set it by using Or, like so:
'. '. Watcher.NotifyFilter = (NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.FileName Or NotifyFilters.DirectoryName) '. '.
In some cases, you will want to have your application continue running while files arrive. I’ve found this to be the most common scenario. To do this, you’ll setup the information mentioned above, then you’ll want to add event handlers for each type of event you wish to capture. These are Changed, Created, Deleted, and Renamed. You can either declared the FileSystemWatcher as WithEvents or you can use AddHandler. WithEvents is handy for having Visual Studio provide the code snippets but is less flexible than using AddHandler. You will need to create the event handler routines for the events you want to handle.
Now that everything is ready, we can begin watching. To do this, we set the EnableRaisingEvents property to True. We can use this property to turn watching on and off.
Here’s our complete code:
Private Watcher As FileSystemWatcher ' ' Other class code here ' Private Sub StartWatcher(ByVal WatchPath As String, ByVal WatchFilter As String) Watcher = New FileSystemWatcher(WatchPath, WatchFilter) Watcher.NotifyFilter = (NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.FileName Or NotifyFilters.DirectoryName) AddHandler Watcher.Created, AddressOf OnCreated AddHandler Watcher.Changed, AddressOf OnModified AddHandler Watcher.Deleted, AddressOf OnModified AddHandler Watcher.Renamed, AddressOf OnRenamed Watcher.EnableRaisingEvents = True End Sub Private Sub OnCreated(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs) 'Code for newly created files here If e.Name = "error.txt" Then 'error file found, do something about it Else 'processing as normal End If End Sub Private Sub OnModified(ByVal sender As Object, ByVal e As System.IO.FileSystemEventArgs) 'Code for changed or deleted files here End Sub Private Sub OnRenamed(ByVal sender As Object, ByVal e As System.IO.RenamedEventArgs) 'Code for renamed file here If e.OldName.Contains("error") Then 're-processing an error file Else 'normal processing End If End Sub
When a file meeting our criteria arrives or is changed in our target folder, the events will fire. We can use the ‘e’ parameter to determine the exact nature of the event and to get the file information as seen in the code for OnCreated and OnRenamed above. Note that the event arguments parameter is different for the Renamed event. It returns information about the new file and the old file.
Sometimes you may want to wait for the arrival of a particular file before allowing your code to continue. You can use the FileSystemWatcher for this as well by using the WaitForChanged method. To use this method you will need to setup the FileSystemWatcher object as before with the path and filters. However, you will not need to add event handlers, but, if they are defined, they will be fired even if EnableRaisingEvents property is set to false.
There are two overloads for the WaitForChanged method. The first overload has a single parameter that indicates the type of event to be watched for, such as created or renamed. The second overload adds the timeout value in milleseconds. I would recommend not using the first since it will wait indefinitely for the event to occur.
Here is an example of using this method:
Dim Results As WaitForChangedResult = Watcher.WaitForChanged(WatcherChangeTypes.Created, 10000) If Results.TimedOut Then 'Operation timed out code Else 'regular processing code End If
Working With Multiple Folders and File Types
Often you’ll have requirements to monitor several different folders. Depending upon your needs, there are a few different ways to handle this.
First, if you’re just monitoring a folder and its subdirectories, you can set the IncludeSubdirectories property to True. This will allow you to add in anything under your main target folder automatically.
What if you need to monitor multiple folders or multiple file types? Unfortunately, each FileSystemWatcher can only monitor one folder structure and one file type. In this case, we will want to create multiple instances of the object to handle each folder and file type combo. Remember though that each of these instances can use the same event handlers.
Tips and Tricks
You can use the InternalBufferSize property to increase the size of the memory buffer for this operation. This can help prevent missing file events in very active systems. However, it can impose memory and performance penalties so be careful about using it.
Keep the size of your event code small. This helps insure better performance and prevents lost events. You may want to consider using threading if the processing required for each file event is considerable.
If a folder is cut and pasted this is considered a rename operation, not a create operation. This has been known to be confusing to some people, particularly when they’re using this method to test their code.
File actions may raise multiple events so you will need to take precautions against processing the same file multiple times.
That’s all for this introduction to the FileSystemWatcher object. Let me know if you have any questions or further observations about this object by leaving me a comment.
Entry Filed under: VB.NET Tutorials
Rate This Article: