Tuesday 10 April 2012

File System Watcher in C#


File System Watcher in C#

There is often a requirement to watch files on an FTP folder and process the file as soon as it arrives.
This can be achieved in two ways. 
Pull Mechanism – for e.g, using Timers, i.e checking the file arrival in its time elapsed event. 
Push Mechanism –for e.g using File System Watcher object.

Both pull and push has its own merits and demerits. One of the biggest drawback of pull mechanism, being the need to check for files at regular interval of time. Which means there is hit at the server periodically and the service consumes system resources unnecessarily.

File system watcher does not fully solve the problem either. The file system watcher is designed in such a way that it triggers an event as soon as there is any activity in the watched folder. In cases where the file size is big and it takes time to upload, processing of the file fails, since it is still being uploaded.

One way to cater to this problem is by blending the Push and Pull mechanism, i.e use of File system watcher and timer both. 
File system watcher triggers an event for any file arrival in the c# application. Which thereby starts a timer. This timer is on demand basis.  The timer would check if the file has been uploaded fully and once done, processe the file. Once all file as processed, stops would itself and wait for another on demand request from File System Watcher.

Sample Code: 

FileSystemWatcher fileWatcherFTP = new FileSystemWatcher();
fileWatcherFTP.Path = directoryToWatch;
fileWatcherFTP.Filter = "*.xml";
fileWatcherFTP.IncludeSubdirectories = true;
fileWatcherFTP.Created += new FileSystemEventHandler(fileWatcherFTP_Changed);
fileWatcherFTP.Changed += new FileSystemEventHandler(fileWatcherFTP_Changed);
fileWatcherFTP.EnableRaisingEvents = true;
                     
timerFTP = new System.Timers.Timer(60000);
timerFTP.Enabled = true;
timerFTP.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timerFTP.Start();


void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
     processFile ();
}

private void processFile()
{
try
{
  DirectoryInfo directoryInfo = new DirectoryInfo(directoryToWatch);
  FileInfo[] files = directoryInfo.GetFiles();
  if (files.Count() == 0)
  {
      // Stop Timer when all files has been processed
    timerFTP.Stop();
    timerFTP.Enabled = false;
  }
  else
  {
    foreach (FileInfo fileInfo in files)
     {
        if (fileUploadCompleted(fileInfo.FullName)) // Check if the upload is complete.
        {
          // process file                        
        }
     }
  }
}
catch (Exception ex){}
}
     
private bool fileUploadCompleted(string filename)
{
  try
  {
   using (FileStream inputStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None))
    {
       return true;
    }
  }
  catch (IOException)
  {
    return false;
  }
}

2 comments:

  1. Isn't it possible with this design to have multiple Timers trying to do the same work (the instantiation is unclear)? Have you considered spinning the FSW event handler off on its own STA thread?

    ReplyDelete
  2. thanks for the good article. Would you please show the implementation of file watcher handler because now you have two event handlers and on your article you only show the implementation of timer event handler.

    ReplyDelete