The FileSystemWatcher .NET class listens to the file system and it is catching any changes and notifications in it. When directories, or files in directories, are changed, events are raised.
When a file is created, the FileSystemWatcher class will normally be notified twice. However, up to 4 or more “events” can be fired depending on which software is used to save the file. This can be difficult to handle because the fired events caused by the same file will run in parallel. For example, if the events started are modifying the file created, only one will be able to open it. It then often happens that a run-time error occurs in one of the other events. The reason is that they are trying to do exactly the same thing with the same file. Again. Some operations just can’t be done more than once, like deleting a file.
Previous FileSystemWatcher solutions
There are plenty of postings on the Internet regarding the problems with FileSystemWatcher. The double or multiple event problem from file creation is an issue. Actually, I think it got worse with faster computers. They can handle events more and more in a truly parallel fashion using multiple processors. But, even after trying all kinds of FileSystemWatcher tricks and tips, copying and pasting from the internet, I still could not get a good behavior on some computers. Furthermore, I thought that many of the solutions suggested (using try-catch, using global Boolean variables to “lock out” or using polling instead), were not good.
The new solution
After giving up the copying and pasting from the Internet, I started to think what should be done using my own brains, instead of copying and pasting.
The idea I came up with was that the parallelism should be removed. Instead, the FileSystemWatcher events should be put in a queue and be taken care of one by one. Interestingly, this can be easily done using so called MONITORS. Actually, I had had happily forgotten about monitors, it’s a long time since I studied, but when searching for semaphores (which I happened to remember) I found out that monitors are more simple and will solve the problem very easily.
Private Sub OnChange(ByVal source As Object, ByVal e As System.IO.FileSystemEventArgs)
SyncLock lockThis
If File.Exists(e.FullPath) Then
GetDataAndDelete(e.FullPath)
End If
End SyncLock
End Sub
Comments
First we declare a variable pointing to type “Object”. When the event is fired, this object locked as soon as the first event is started. Any other event trying to access it (or even trying to lock it) will have to wait at that point in the code until the object is unlocked. As soon as it is released, the next event in line will then hold the object and proceed. The other ones in the queue have to wait. In visual basic this is called SyncLock which may actually be a better name than Monitor.
In this case, the testing condition was just to see if the file existed becuase in “GetDataAndDelete”, the file will be deleted. Therefore, you may need more advanced conditions to see if it is the same filename coming again (within a short period of time).
Hope you like it!