Sunday, October 14, 2007

Tip in using FileSystemWatcher class, make use of InternalBufferSize

There are a few gotchas in implementing FileSystemWatcher. One of them that I have recently encountered is the use of InternalBufferSize property. Previously, I built a windows service that watches for new files created in a directory. The files are then processed and the data uploaded to a sql server database. During my testing and initial deploy, I didn't see any issue nor did I think of any potential problems. Until one day I noticed that it is not picking up all the files. Some files are being left out at random. After some investigation, I found out that this is happening because of an overflow in the buffer that supports the FileSystemWatcher. The default setting for this property is only at 8K, imagine it has to keep track of all the events and info about the files. Approximately according to this, 8K can only hold info for as much as 80 files at one time. So for me, my solution is to increase the buffer size to 32K, which is 32768. The setting should be in multiples of 4K as noted in msdn.

Here's how I implemented the class:

public partial class NXPFileWatcher : ServiceBase

    {

        FileSystemWatcher FSWatcher = null;

 

        public NXPFileWatcher()

        {

            InitializeComponent();

        }

 

        protected override void OnStart(string[] args)

        {

            try

            {

                FSWatcher = new FileSystemWatcher();

                FSWatcher.Path = ConfigurationManager.AppSettings["WatchPath"];

                FSWatcher.InternalBufferSize = 32768;

                FSWatcher.NotifyFilter = NotifyFilters.CreationTime;

                FSWatcher.Filter = "*.xml";

                FSWatcher.Created += new FileSystemEventHandler(FSWatcher_Created);

                FSWatcher.EnableRaisingEvents = true;

                SendNotification("has Started");

            }

            catch (Exception ex)

            {

                Log.Write(ex.Message);

            }

        }

 

        protected override void OnStop()

        {

            try

            {

                FSWatcher.Dispose();

                SendNotification("has Stopped");

            }

            catch (Exception ex)

            {

                Log.Write(ex.Message);

            }

        }

 

        protected override void OnPause()

        {

            OnStop();

        }

 

        protected override void OnContinue()

        {

            OnStart(null);

        }

 

        protected override void OnShutdown()

        {

            try

            {

                FSWatcher.Dispose();

                SendNotification("has stopped due to system shutting down");

            }

            catch (Exception ex)

            {

                Log.Write(ex.Message);

            }

        }

 

        private void FSWatcher_Created(object sender, FileSystemEventArgs e)

        {

            // Now open the file

            XmlFile xml = new XmlFile();

            xml.FullPath = e.FullPath;

            xml.Process();

        }

    }