Tuesday, September 11, 2007

FileSystemWatcher problem

Did you have a task for monitoring files?
The FileSystemWatcher class has a great features, but also some outages. The problem is that creating/copying/moving files arround is hard taks and the watcher raises couple of events.
The most important events in my case were "created" and "changed". The problem is that the "Created" event is fired when the file is started being created, not when finished being created. After the created, there would several "changed" events depending on the file size. So how could we possibly know when the file is realy created, full and ready to work with it?

There are several posts and examples arround the net like:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2123580&SiteID=1&mode=1
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=659823&SiteID=1

What is my approach?
After catching any event - you just stop monitoring for FSWEvents and start a timer. On every tick you try to open the file for reading. If you cannot - increase the timer interval. You can also add a code to monitor the total time elapsed since the first try to open the file, but the provided code does not do that.

So here it is - one of the approached to more correctly monitor for files:

 

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security;
using System.Timers;

namespace MonitorTest
{
    public class Program
    {
        private FileSystemWatcher _watch;
        private string _watchPath = @"d:\temp\";
        private string _watchFile = "SomeFile.txt"
        private Timer _timer;
        private DateTime _started;
        private TimeSpan _totalTime;
        private void StartTrying()
        {
            _started = DateTime.Now;
            _totalTime = TimeSpan.Zero; 
            _timer = new Timer();
            _timer.Interval = 1000;
            _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
            _timer.Enabled = true;
        } 
        void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            string FullPath = string.Format("{0}{1}", _watchPath, _watchFile);
            FileInfo fi = new FileInfo(FullPath);
            StreamReader r = null;
            _totalTime = DateTime.Now - _started; 
            Console.WriteLine("Trying? {0}", _totalTime);
            try
            {
                r = fi.OpenText();
                r.Close();
                r.Dispose();
                _timer.Enabled = false;
                Console.WriteLine("File is free for reading after: {0} timespan?",_totalTime);
            }
            catch (IOException ioex)
            {
                Console.WriteLine("Cannot open ? {0}", ioex.Message);
                _timer.Enabled = true;
                _timer.Interval += 1000;
            }
            finally
            {
                if (r != null)
                {
                    r.Close();
                    r.Dispose();
                }
            }
        } 
        private void OnChanged(object source, FileSystemEventArgs e)
        {
            // Specify what is done when a file is changed, created, or eleted.
            FileSystemWatcher wo = source as FileSystemWatcher;
            FileInfo fi = new FileInfo(e.FullPath); 
            if (wo != null)
            {
                switch (e.ChangeType)
                {
                    case WatcherChangeTypes.Changed:
                        Console.WriteLine("File {0}{1} was changed? {2} 3}", _watchPath, _watchFile, fi.LastAccessTime ,wo.NotifyFilter);
                        StartTrying();
                        _watch.EnableRaisingEvents = false;
                        break;
                    case WatcherChangeTypes.Renamed:
                        Console.WriteLine("File {0}{1} was renamed? {2}",
_watchPath, _watchFile, source);
                        StartTrying();
                        _watch.EnableRaisingEvents = false;
                        break;
                    case WatcherChangeTypes.Deleted:
                        Console.WriteLine("File {0}{1} was deleted? {2}",
_watchPath, _watchFile, source);
                        StartTrying();
                        _watch.EnableRaisingEvents = false;
                        break;
                    case WatcherChangeTypes.Created:
                        Console.WriteLine("File {0}{1} was created? {2}", _watchPath, _watchFile, source);
                        StartTrying();
                        _watch.EnableRaisingEvents = false;
                        break;
                }
            }
        } 
        public Program()
        {
            _watch = new FileSystemWatcher(_watchPath);
            _watch.Filter = _watchFile;
            _watch.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
            _watch.Changed += new FileSystemEventHandler(OnChanged);
            _watch.Created += new FileSystemEventHandler(OnChanged);
            _watch.Deleted += new FileSystemEventHandler(OnChanged);
            _watch.EnableRaisingEvents = true; 
        } 
        static void Main(string[] args)
        {
            Program p = new Program();
            Console.ReadLine();
        }
    }
}

No comments: