Sunday, January 07, 2007
FileCreationWatcher
A few weeks ago, I received an e-mail from someone who asked me if I could give more details about a class I created at work, that is essentially a wrapper around the FileSystemWatcher class, and that detects the creation of files more reliably. You can read a discussion about this on Channel 9, in this thread. I sent him an e-mail back, with a simplified version of the wrapper class, and because I think this could also be useful for other people, I decided to post it here.
public class FileCreationWatcher : IDisposable { FileSystemWatcher fWatcher; public FileCreationWatcher(string path, string filter) { Initialize(path, filter); } void Initialize(string path, string filter) { fWatcher = new FileSystemWatcher(path, filter); fWatcher.Created += OnFileCreated; fWatcher.Error += OnError; } void OnFileCreated(object sender, FileSystemEventArgs e) { FileInfo lFile = new FileInfo(e.FullPath); if (lFile.Exists) { // schedule the processing on a different thread ThreadPool.QueueUserWorkItem(delegate { while(true) { // wait 100 milliseconds between attempts to read Thread.Sleep(TimeSpan.FromMilliseconds(100)); try { // try to open the file lFile.OpenRead().Close(); break; } catch(IOException) { // if the file is still locked, keep trying continue; } } // the file can be opened successfully: raise the event if (Created != null) Created(this, e); }); } } void OnError(object sender, ErrorEventArgs e) { // when an error occurs, the current FileSystemWatcher is disposed, // and a new one is created string lPath = fWatcher.Path; string lFilter = fWatcher.Filter; fWatcher.Dispose(); Initialize(lPath, lFilter); } public void Start() { fWatcher.EnableRaisingEvents = true; } public void Stop() { fWatcher.EnableRaisingEvents = false; } public event FileSystemEventHandler Created; #region IDisposable Members public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~FileCreationWatcher() { Dispose(false); } protected virtual void Dispose(bool disposing) { if (disposing) fWatcher.Dispose(); } #endregion }

