You need to monitor a directory, watching for any files that are added, removed, or changed.
Sample code folder: Chapter 14\FileWatcher
Use a FileSystemWatcher object and its events notify you of any changes in a specific directory or to specific files. System.IO.FileSystemWatcher includes many properties that let you adjust the types of files or changes to monitor. It also includes distinct events for most types of changes.
The code in this recipe implements a simple test program that watches for any change in a selected directory. Create a new Windows Forms application, and add the following controls to Form1:
Add additional labels, if desired, and arrange the form to look like the one in Figure 14-7.
Open the source-code file for the form, and add the following code to the Form1 class template:
Public WithEvents WatchForChanges As IO.FileSystemWatcher Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ' ----- Add the types of actions. The Enum class's ' GetNames method returns a collection of the ' enumeration type's members as strings. Since ' "Enum" is a keyword in Visual Basic, the ' "Enum" class must be escaped with brackets. For Each scanFilters As String In [Enum].GetNames( _ GetType(IO.NotifyFilters)) WatchFor.Items.Add(scanFilters)
Figure 14-7. Controls for the directory watcher sample
Next scanFilters End Sub Private Sub StartStop_Click(ByVal sender As System. Object, _ ByVal e As System.EventArgs) Handles StartStop.Click ' ----- Start or stop watching a directory. Dim monitorEvents As Integer = 0 If (StartStop.Text = "Start") Then ' ----- Check for valid settings. If (My.Computer.FileSystem.DirectoryExists( _ WatchDirectory.Text) = False) Then MsgBox("Please specify a valid directory.") Exit Sub End If If (WatchFor.SelectedItems.Count = 0) Then MsgBox("Please specify the events to watch for.") Exit Sub End If ' ----- Build the events setting. The Enum class's ' Parse( ) method converts a string back to its ' Integer enumeration value, in this case, ' from the IO.NotifyFilters enumeration. For Each scanEvents As String In WatchFor.CheckedItems monitorEvents = monitorEvents Or _ CInt([Enum].Parse(GetType(IO.NotifyFilters), _ scanEvents)) Next scanEvents ' ----- Start the watching process. DirectoryEvents.Items.Clear( ) WatchForChanges = New IO. FileSystemWatcher WatchForChanges.SynchronizingObject = Me WatchForChanges.Path = WatchDirectory.Text WatchForChanges.Filter = WatchFilter.Text WatchForChanges.NotifyFilter = monitorEvents WatchForChanges.IncludeSubdirectories = IncludeSubdirectories.Checked WatchForChanges.EnableRaisingEvents = True StartStop.Text = "Stop" Else ' ----- End the watching process. WatchForChanges.EnableRaisingEvents = False WatchForChanges.Dispose( ) WatchForChanges = Nothing StartStop.Text = "Start" End If End Sub Private Sub WatchForChanges_Changed(ByVal sender As Object, _ ByVal e As System.IO. FileSystemEventArgs) _ Handles WatchForChanges.Changed DirectoryEvents.Items.Add("Changed: " & e.Name) End Sub Private Sub WatchForChanges_Created(ByVal sender As Object, _ ByVal e As System.IO.FileSystemEventArgs) _ Handles WatchForChanges.Created DirectoryEvents.Items.Add("Created: " & e.Name) End Sub Private Sub WatchForChanges_Deleted(ByVal sender As Object, _ ByVal e As System.IO.FileSystemEventArgs) _ Handles WatchForChanges.Deleted DirectoryEvents.Items.Add("Deleted: " & e.Name) End Sub Private Sub WatchForChanges_Renamed(ByVal sender As Object, _ ByVal e As System.IO.RenamedEventArgs) _ Handles WatchForChanges.Renamed DirectoryEvents.Items.Add("Renamed: " & e.OldName & _ " to " & e.Name) End Sub
To use the program, enter a valid directory in the WatchDirectory field, optionally enter a filename or wildcard in the WatchFilter field, and select one or more entries in the WatchFor list. Now click the StartStop button, and begin making changes in the target directory.
The FileSystemWatcher class monitors activity in a specific directory and raises events based on changes in that directory. The class often reports any change immediately. This means that if you create a new file in the directory and take several minutes to fill it with data before closing it, FileSystemWatcher will report the creation of the file at the start of its life, not when it was closed. This can lead to interaction issues in your program. When you receive notification of a new file in a monitored directory, you should confirm that the complete file has been written out before processing it.
The FileSystemWatcher class uses a shared memory buffer for part of its processing. This buffer is limited in size, so if you experience a lot of changes in a directory, the buffer may "overflow, " and you will lose notifications. The object includes an Error event that will let you know when this happens. Also, you can adjust the InternalBufferSize property to allocate more buffer space.
The Toolbox displayed for a Windows Forms form in Visual Studio includes a FileSystemWatcher control. This control is the same as the class included in this recipe's sample code. If you choose to declare the object through code instead of as a control, make sure you set its SynchronizingObject property to the active form (as is done in the sample code) to prevent intrathread errors.