One of the things that has long bugged me about the FileSystemWatcher is the way it fires multiple events for a single logical change to a file. I know why it happens, but I don’t want to have to care – I just want to reparse the file once, not 4-6 times in a row. Ideally, there would be an event that only fires when a given file is done changing, rather than every step along the way.
Over the years I’ve come up with various solutions to this problem, of varying degrees of ugliness. I thought Reactive Extensions would be the ultimate solution, but there’s something I’m not doing right, and I’m hoping someone can point out my mistake.
I have an extension method:
public static IObservable<IEvent<FileSystemEventArgs>> GetChanged(this FileSystemWatcher that)
{
return Observable.FromEvent<FileSystemEventArgs>(that, "Changed");
}
Ultimately, I would like to get one event per filename, within a given time period – so that four events in a row with a single filename are reduced to one event, but I don’t lose anything if multiple files are modified at the same time. BufferWithTime sounds like the ideal solution.
var bufferedChange = watcher.GetChanged()
.Select(e => e.EventArgs.FullPath)
.BufferWithTime(TimeSpan.FromSeconds(1))
.Where(e => e.Count > 0)
.Select(e => e.Distinct());
When I subscribe to this observable, a single change to a monitored file triggers my subscription method four times in a row, which rather defeats the purpose. If I remove the Distinct() call, I see that each of the four calls contains two identical events – so there is some buffering going on. Increasing the TimeSpan passed to BufferWithTime seems to have no effect – I went as high as 20 seconds without any change in behavior.
This is my first foray into Rx, so I’m probably missing something obvious. Am I doing it wrong? Is there a better approach? Thanks for any suggestions…
My mistake. Somehow I’ve got multiple FileSystemWatchers monitoring each other’s folders. The observable was triggering once for each watcher, but
BufferWithTimeappears to be working correctly. I still need to figure out why my watchers are firing events for folders I thought they were configured to ignore, but that’s got nothing to do with Rx or this question.In fact, maybe I can punt on that problem, and switch to having a single watcher monitoring a parent folder, using Rx to filter out events from folders I’m not interested in.