用了线程安全的hashtable来处理一次改变触发两次事件的问题,要注意的是在实际项目使用中,在通过监控文件事情触发时开一个线程watcherprocess去处理自己业务逻辑的时候,不管业务逻辑成功或者失败(例如有异常抛出一定要try一下)一定要让watcherprocess的 completed也就是myfilesystemwather的watcherprocess_oncompleted执行去移除对应变化文件的hashtable的key,不然下次此文件改变时是无法触发你的业务逻辑的。
还有就是在进行文件监控的时候, 被监控文件在写入的时候,是会有i/o冲突的,即使写入文件是fileshare.read的也会出现,要真正解决貌似只有filemaping方法,但是我的项目中文本的写入软件不是我们能控制的,所以只有用处理异常的方法来解决。
using system;
using system.io;
namespace test
{
class program
{
static void main(string[] args)
{
watcherstrat(@"c:test", "*.txt");
//由于是控制台程序,加个输入避免主线程执行完毕,看不到监控效果
console.readkey();
}
private static void watcherstrat(string path, string filter)
{
filesystemwatcher watcher = new filesystemwatcher();
watcher.path = path;
watcher.filter = filter;
watcher.changed += new filesystemeventhandler(onprocess);
watcher.created += new filesystemeventhandler(onprocess);
watcher.deleted += new filesystemeventhandler(onprocess);
watcher.renamed += new renamedeventhandler(onrenamed);
watcher.enableraisingevents = true;
}
private static void onprocess(object source, filesystemeventargs e)
{
if (e.changetype == watcherchangetypes.created)
{
oncreated(source, e);
}
else if (e.changetype == watcherchangetypes.changed)
{
onchanged(source, e);
}
else if (e.changetype == watcherchangetypes.deleted)
{
ondeleted(source, e);
}
}
private static void oncreated(object source, filesystemeventargs e)
{
console.writeline("文件新建事件处理逻辑");
}
private static void onchanged(object source, filesystemeventargs e)
{
console.writeline("文件改变事件处理逻辑");
}
private static void ondeleted(object source, filesystemeventargs e)
{
console.writeline("文件删除事件处理逻辑");
}
private static void onrenamed(object source, renamedeventargs e)
{
console.writeline("文件重命名事件处理逻辑");
}
}
}
myfilesystemwather类:
using system;
using system.collections;
using system.io;
using system.threading;
namespace test
{
public delegate void completed(string key);
public class myfilesystemwather
{
private filesystemwatcher fswather;
private hashtable hstbwather;
public event renamedeventhandler onrenamed;
public event filesystemeventhandler onchanged;
public event filesystemeventhandler oncreated;
public event filesystemeventhandler ondeleted;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="path">要监控的路径</param>
public myfilesystemwather(string path, string filter)
{
if (!directory.exists(path))
{
throw new exception("找不到路径:" + path);
}
hstbwather = new hashtable();
fswather = new filesystemwatcher(path);
// 是否监控子目录
fswather.includesubdirectories = false;
fswather.filter = filter;
fswather.renamed += new renamedeventhandler(fswather_renamed);
fswather.changed += new filesystemeventhandler(fswather_changed);
fswather.created += new filesystemeventhandler(fswather_created);
fswather.deleted += new filesystemeventhandler(fswather_deleted);
}
/// <summary>
/// 开始监控
/// </summary>
public void start()
{
fswather.enableraisingevents = true;
}
/// <summary>
/// 停止监控
/// </summary>
public void stop()
{
fswather.enableraisingevents = false;
}
/// <summary>
/// filesystemwatcher 本身的事件通知处理过程
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void fswather_renamed(object sender, renamedeventargs e)
{
lock (hstbwather)
{
hstbwather.add(e.fullpath, e);
}
watcherprocess watcherprocess = new watcherprocess(sender, e);
watcherprocess.oncompleted += new completed(watcherprocess_oncompleted);
watcherprocess.onrenamed += new renamedeventhandler(watcherprocess_onrenamed);
thread thread = new thread(watcherprocess.process);
thread.start();
}
private void watcherprocess_onrenamed(object sender, renamedeventargs e)
{
onrenamed(sender, e);
}
private void fswather_created(object sender, filesystemeventargs e)
{
lock (hstbwather)
{
hstbwather.add(e.fullpath, e);
}
watcherprocess watcherprocess = new watcherprocess(sender, e);
watcherprocess.oncompleted += new completed(watcherprocess_oncompleted);
watcherprocess.oncreated += new filesystemeventhandler(watcherprocess_oncreated);
thread threaddeal = new thread(watcherprocess.process);
threaddeal.start();
}
private void watcherprocess_oncreated(object sender, filesystemeventargs e)
{
oncreated(sender, e);
}
private void fswather_deleted(object sender, filesystemeventargs e)
{
lock (hstbwather)
{
hstbwather.add(e.fullpath, e);
}
watcherprocess watcherprocess = new watcherprocess(sender, e);
watcherprocess.oncompleted += new completed(watcherprocess_oncompleted);
watcherprocess.ondeleted += new filesystemeventhandler(watcherprocess_ondeleted);
thread tddeal = new thread(watcherprocess.process);
tddeal.start();
}
private void watcherprocess_ondeleted(object sender, filesystemeventargs e)
{
ondeleted(sender, e);
}
private void fswather_changed(object sender, filesystemeventargs e)
{
if (e.changetype == watcherchangetypes.changed)
{
if (hstbwather.containskey(e.fullpath))
{
watcherchangetypes oldtype = ((filesystemeventargs)hstbwather[e.fullpath]).changetype;
if (oldtype == watcherchangetypes.created || oldtype == watcherchangetypes.changed)
{
return;
}
}
}
lock (hstbwather)
{
hstbwather.add(e.fullpath, e);
}
watcherprocess watcherprocess = new watcherprocess(sender, e);
watcherprocess.oncompleted += new completed(watcherprocess_oncompleted);
watcherprocess.onchanged += new filesystemeventhandler(watcherprocess_onchanged);
thread thread = new thread(watcherprocess.process);
thread.start();
}
private void watcherprocess_onchanged(object sender, filesystemeventargs e)
{
onchanged(sender, e);
}
public void watcherprocess_oncompleted(string key)
{
lock (hstbwather)
{
hstbwather.remove(key);
}
}
}
}
path——这个属性告诉filesystemwatcher它需要监控哪条路径。例如,如果我们将这个属性设为“c:test”,对象就监控test目录下所有文件发生的所有改变(包括删除,修改,创建,重命名)。
filter——这个属性允许你过滤掉某些类型的文件发生的变化。例如,如果我们只希望在txt文件被修改/新建/删除时提交通知,可以将这个属性设为“*txt”。在处理高流量或大型目录时,使用这个属性非常方便。
notifyfilter——获取或设置要监视的更改类型。可以进一步的过滤要监控的更改类型,如watcher.notifyfilter = notifyfilters.lastaccess | notifyfilters.lastwrite
changed——当被监控的目录中有一个文件被修改时,就提交这个事件。值得注意的是,这个事件可能会被提交多次,即使文件的内容仅仅发生一项改变。这是由于在保存文件时,文件的其它属性也发生了改变。
created——当被监控的目录新建一个文件时,就提交这个事件。如果你计划用这个事件移动新建的事件,你必须在事件处理器中写入一些错误处理代码,它能处理当前文件被其它进程使用的情况。之所以要这样做,是因为created事件可能在建立文件的进程释放文件之前就被提交。如果你没有准备正确处理这种情况的代码,就可能出现异常。
注:如果你没有将enableraisingevents设为真,系统不会提交任何一个事件。如果有时filesystemwatcher对象似乎无法工作,请首先检查enableraisingevents,确保它被设为真。
当filesystemwatcher调用一个事件处理器时,它包含两个自变量——一个叫做“sender”的对象和一个叫做“e”的 filesystemeventargs对象。我们感兴趣的自变量为filesystemeventargs自变量。这个对象中包含有提交事件的原因。以下是filesystemeventargs对象的一些属性:
注意:filesystemeventargs对象是监控文件夹下有文件创建、删除、修改时的自变量,如果是重命名的话为renamedeventargs对象此时除了filesystemeventargs对象的属性值,多了一个oldfullpath,为重命名之前的文件名。