PDA

View Full Version : File watcher?


CNemo7539
06-28-2007, 09:10 PM
Is there any helper class to track changes in configuration files?
I would like to have ability respond automatically when files where edited.

I guess I can do it with FileSystemWatcher just wonder if somebody did it already.

CNemo7539
06-29-2007, 06:38 PM
I've created quick and dirty file watcher.


using System;
using System.Collections;
using Spring.Context;
using Spring.Context.Support;
using System.IO;
using System.Reflection;

namespace ContextRefresh
{
class FileWatcherCollection : CollectionBase, IList
{
private event FileSystemEventHandler _changed;

public FileWatcherCollection(FileSystemEventHandler handler)
{
_changed += handler;
}

int IList.Add(object value)
{
string s = value.ToString();
if (File.Exists(s))
{
return InnerList.Add(CreateWatcher(s));
}
else
{
return -1;
}
}

private FileWatcher CreateWatcher(string value)
{
return new FileWatcher(value, _changed);
}
}

class FileWatcher : FileSystemWatcher
{
private bool _refreshing;
private event FileSystemEventHandler _changed;

public FileWatcher(string fileName, FileSystemEventHandler handler):
base((new FileInfo(Assembly.GetExecutingAssembly().Location) ).DirectoryName)
{
_changed = handler;
this.Filter = fileName;
this.NotifyFilter = NotifyFilters.LastAccess; //Is this enough?
this.Changed += new FileSystemEventHandler(OnChanged);
this.EnableRaisingEvents = true;
}

private void OnChanged(object sender, FileSystemEventArgs e)
{
if (!_refreshing && _changed != null)
{
_refreshing = true;
try
{
_changed(sender, e);
}
finally
{
_refreshing = false;
}
}
}
}

/// <summary>
/// Define object of this class somewhere in configuration
/// </summary>
class ConfigChangeWatcher: IApplicationContextAware
{
private IApplicationContext _context;
private FileWatcherCollection _watchers;

public ConfigChangeWatcher()
{
_watchers = new FileWatcherCollection(new FileSystemEventHandler(OnFileChanged));
}

#region IApplicationContextAware Members

public IApplicationContext ApplicationContext
{
get
{
return _context;
}
set
{
_context = value;
}
}
#endregion

/// <summary>
/// <para>List of the files to watch.</para>
/// <para>
/// This collection must be initialized in object definition in configuration file.
/// File names are relative to assembly directory.
/// </para>
/// <para>
/// <property name="FileNames">
/// <list>
/// <value>FileOne</value>
/// <value>FileTwo</value>
/// </list>
/// </property>
/// </para>
/// </summary>
public FileWatcherCollection FileNames
{
get
{
return _watchers;
}
}

private void OnFileChanged(object sender, FileSystemEventArgs e)
{
((XmlApplicationContext)_context).Refresh();
}
}
}



<object id="ConfigWatcher" type="ContextRefresh.ConfigChangeWatcher, ContextRefresh">
<property name="FileNames">
<list>
<value>Validation.xml</value>
<value>Objects.xml</value>
</list>
</property>
</object>


Will be nice if somebody can comment. I wonder if this will be enough.

Erich Eichinger
07-04-2007, 07:46 AM
Hi,

cool stuff - I had adding such a class to spring in my mind for a while now.

There's one important improvement: A filechange event is raised as soon as a process *starts* modifiying a file. With your implementation one would end up reading a file before the write may have completed.

I don't know about a 100% reliable solution, but the samples I found all fired up a timer in case of a filechange and do the reread within the timer-event with a ~1s delay. Look into e.g. log4net config file watcher for a sample implementation.

cheers,
Erich

CNemo7539
07-05-2007, 06:37 PM
Thanks for your note!

I'll take a look on it. As I said that code was fast and dirty, just to proove concept.