August 19, 2011

FileSystemWatcher

File system watcher hints and tips
Msdn page for it has some useful information on gotchas

Following sample code watches a file and fires events when the file "appears" or "disappears". In this case the file could "appear" when it is created or when it is renamed from an existing file and "disappear" if it is deleted or the file is renamed to something else.

This renaming issue is something to watch out for when using this class! Detecting this is a bit more subtle.
//class fields
FileSystemWatcher fileWatcher = new FileSystemWatcher();
// Target a specific file (in this case)
readonly string targetFileName = "Myfile.name";
string targetDirectory;
string fullTargetFilePath;
...
// Expose some events
public event EventHandler LockFileAppeared;
public event EventHandler LockFileDisappeared;

// Private Firing events
void FireLockFileAppeared(FileSystemEventArgs eargs)
{
  if (LockFileAppeared != null)
    LockFileAppeared(this, eargs);
}

void FireLockFileDisappeared(FileSystemEventArgs eargs)
{
  if (LockFileDisappeared != null)
    LockFileDisappeared(this, eargs);
}
...
// Initialise it
void InitialiseFileWatcher()
{
  if (Directory.Exists(this.targetDirectory))
  {
    this.fullTargetFilePath = System.IO.Path.Combine(
            LockFileDirectory, LockFileName);
    fileWatcher.Path = LockFileDirectory;
    fileWatcher.Filter = LockFileName; 
    fileWatcher.IncludeSubdirectories = false;
    fileWatcher.Renamed += new RenamedEventHandler(fileWatcher_Renamed);
    fileWatcher.Error += new ErrorEventHandler(fileWatcher_Error);
    fileWatcher.Created += new FileSystemEventHandler(fileWatcher_Created);
    fileWatcher.Deleted += new FileSystemEventHandler(fileWatcher_Deleted);
    fileWatcher.EnableRaisingEvents = true;
  }
}

// Implement a IDisposable as FileSystemWatcher is disposable
...
// Add events
void fileWatcher_Deleted(object sender, FileSystemEventArgs e)
{ // FIRED ON ANOTHER THREAD
  if (e.Name == LockFileName)
    FireLockFileDisappeared(e);
}

void fileWatcher_Created(object sender, FileSystemEventArgs e)
{ // FIRED ON ANOTHER THREAD
  if (e.Name == LockFileName)
    FireLockFileAppeared(e);
}

void fileWatcher_Renamed(object sender, RenamedEventArgs e)
{ // FIRED ON ANOTHER THREAD
  // If another file is renamed to our target file 
  if (e.Name == LockFileName)
  {
    FireLockFileAppeared(new FileSystemEventArgs(
      WatcherChangeTypes.Created, LockFileDirectory, LockFileName));
  }
  // If our target file is renamed to something else
  else if (e.OldName == LockFileName)
  {
    FireLockFileDisappeared(new FileSystemEventArgs(
      WatcherChangeTypes.Deleted, LockFileDirectory, LockFileName));
  }
}

// Misc. helpers
public string LockFilePath
{
    get { return this.fullTargetFilePath; }
}

public string LockFileDirectory
{
    get { return this.targetDirectory; }
}

Be aware that the class events are fired on another thread so if you want to update the GUI you will have to marshal any data accross. Also be aware that sometimes the events can be fired multiple times for only 1 real event.

No comments: