The last four posts have presented an engineering project for a seemingly simple task: watching a directory for new files so another task can process them. I've packaged the source so you can download it here: Fws.Collections.zip (208.71 kb) [updated 25-Mar-2013 with thanks to Gavin Aiken].
The files include
- WatchedFileCollection, the class that started this series. It wraps a FileSystemWatcher and presents its events in an IEnumerable<string>. In the original post, WatchedFileCollection contained the code for the next three classes. I have since decided that each is useful on its own, so I made separate classes out of them.
- CancellableQueue, encapsulating a ConcurrentQueue from which items can be dequeued subject to a CancellationToken.
- CancellableFileSystemEventQueue, a CancellableQueue specialized for the events from a FileSystemWatcher.
- CreatedFileCollection, derived from WatchedFileCollection to present only the FileSystemWatcher's Created events.
- ChangedFileCollection, also derived from WatchedFileCollection but for file-change events reported by the FileSystemWatcher. I did not present this class in the series, but it's here as a bonus.
- TimedDistinctCollection, which I discussed in the second post, How to Filter Long-Running IEnumerables for Distinct Objects.
- ReadyItemCollection, discussed in the third post, How to Apply a Gate to An IEnumerable<T>. It is an IEnumerable<T> that presents items from an input IEnumerable<T> only as they are "ready".
- ReadyFileCollection, derived from ReadyItemCollection and specialized for files, as discussed in the fourth post.
The ZIP also includes a complete unit-testing project.
One final note before we leave this series. Here is an example of putting all the classes together to create an IEnumerable pipe that yields files matching "*.txt" from a source directory, waiting for each one to have had no activity for at least 2 minutes, and retaining a 5-minute memory of file names for the purpose of detecting duplicates.
string sourceDir = @"C:\Some\Directory";
string filePattern = "*.txt";
var quiesceTime = TimeSpan.FromMinutes(2);
var dupeTime = TimeSpan.FromMinutes(5);
var files =
new ReadyFileCollection(
new TimedDistinctCollection<string>(
new CreatedFileCollection(cts.Token, sourceDir, filePattern),
dupeTime,
fileName => fileName),
cts.Token,
quiesceTime);
foreach (var file in files)
{
// Do something
}