最近在项目中有这么个需求,就是得去实时获取某个在无规律改变的文本文件中的内容。首先想到的是用程序定期去访问这个文件,因为对实时性要求很高,间隔不能超过1S,而且每次获取到文本内容都要去分发给web服务器做别的操作,而那个文本的写入有时候会频繁,1秒可能多次,但是也有可能在相当长一段时间内是没有任何写入的。

这样一来如果每秒都去访问文件的话,一个是IO问题,还有就是每次操作都会引起后端一系列程序的反应,文本在长时间内无写入的话,一秒一次的触发一系列徒劳的事情太不可取了。

最终发现了c#中的FileSystemWatcher对象,在应用FileSystemWatcher之前,首先了解一下这个对象的基本属性和事件,首先普及一下FileSystemWatcher基本知识。

FileSystemWatcher基础

属性:

Path——这个属性告诉FileSystemWatcher它需要监控哪条路径。例如,如果我们将这个属性设为“C:\test”,对象就监控test目录下所有文件发生的所有改变(包括删除,修改,创建,重命名)。

IncludeSubDirectories——这个属性说明FileSystemWatcher对象是否应该监控子目录中(所有文件)发生的改变。

Filter——这个属性允许你过滤掉某些类型的文件发生的变化。例如,如果我们只希望在TXT文件被修改/新建/删除时提交通知,可以将这个属性设为“*txt”。在处理高流量或大型目录时,使用这个属性非常方便。

NotifyFilter——获取或设置要监视的更改类型。可以进一步的过滤要监控的更改类型,如watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite

| NotifyFilters.FileName | NotifyFilters.DirectoryName;

事件:

Changed——当被监控的目录中有一个文件被修改时,就提交这个事件。值得注意的是,这个事件可能会被提交多次,即使文件的内容仅仅发生一项改变。这是由于在保存文件时,文件的其它属性也发生了改变。

Created
——当被监控的目录新建一个文件时,就提交这个事件。如果你计划用这个事件移动新建的事件,你必须在事件处理器中写入一些错误处理代码,它能处理当前文件
被其它进程使用的情况。之所以要这样做,是因为Created事件可能在建立文件的进程释放文件之前就被提交。如果你没有准备正确处理这种情况的代码,就
可能出现异常。

Deleted——当被监控的目录中有一个文件被删除,就提交这个事件。

Renamed——当被监控的目录中有一个文件被重命名,就提交这个事件。

注:如果你没有将EnableRaisingEvents设为真,系统不会提交任何一个事件。如果有时FileSystemWatcher对象似乎无法工作,请首先检查EnableRaisingEvents,确保它被设为真。

事件处理

FileSystemWatcher调用一个事件处理器时,它包含两个自变量——一个叫做“sender”的对象和一个叫做“e”的
FileSystemEventArgs对象。我们感兴趣的自变量为FileSystemEventArgs自变量。这个对象中包含有提交事件的原因。以
下是FileSystemEventArgs对象的一些属性:

属性:
Name——这个属性中使事件被提交的文件的名称。其中并不包含文件的路径——只包含使用事件被提交的文件或目录名称。

ChangeType——这是一个WatcherChangeTypes,它指出要提交哪个类型的事件。其有效值包括:

Changed

Created

Deleted

Renamed

FullPath——这个属性中包含使事件被提交的文件的完整路径,包括文件名和目录名。


意:FileSystemEventArgs对象是监控文件夹下有文件创建、删除、修改时的自变量,如果是重命名的话为RenamedEventArgs
对象此时除了FileSystemEventArgs对象的属性值,多了一个OldFullPath,为重命名之前的文件名。

以上为FileSystemEventArgs的基本知识,大部分是从网上搜找的然后自己稍微整理了一下。

下面为简单用法:
01 using System;

02 using System.IO;

03

04 namespace test

05 {

06 class Program

07 {

08 static void Main(string[] args)

09 {

10

11

12 WatcherStrat(@"C:\test", "*.txt");

13 //由于是控制台程序,加个输入避免主线程执行完毕,看不到监控效果

14 Console.ReadKey();

15

16 }

17

18

19

20 private static void WatcherStrat(string path, string filter)

21 {

22 FileSystemWatcher watcher = new FileSystemWatcher();

23 watcher.Path = path;

24

25 watcher.Filter = filter;

26

27 watcher.Changed += new FileSystemEventHandler(OnProcess);

28 watcher.Created += new FileSystemEventHandler(OnProcess);

29 watcher.Deleted += new FileSystemEventHandler(OnProcess);

30 watcher.Renamed += new RenamedEventHandler(OnRenamed);

31

32 watcher.EnableRaisingEvents = true;

33 }

34

35

36

37

38 private static void OnProcess(object source, FileSystemEventArgs e)

39 {

40 if (e.ChangeType == WatcherChangeTypes.Created)

41 {

42 OnCreated(source, e);

43

44 }

45 else if (e.ChangeType == WatcherChangeTypes.Changed)

46 {

47 OnChanged(source, e);

48

49 }

50 else if (e.ChangeType == WatcherChangeTypes.Deleted)

51 {

52 OnDeleted(source, e);

53

54 }

55 }

56

57 private static void OnCreated(object source, FileSystemEventArgs e)

58 {

59

60 Console.WriteLine("文件新建事件处理逻辑");

61

62 }

63

64 private static void OnChanged(object source, FileSystemEventArgs e)

65 {

66

67 Console.WriteLine("文件改变事件处理逻辑");

68 }

69

70 private static void OnDeleted(object source, FileSystemEventArgs e)

71 {

72

73 Console.WriteLine("文件删除事件处理逻辑");

74 }

75

76 private static void OnRenamed(object source, RenamedEventArgs e)

77 {

78

79 Console.WriteLine("文件重命名事件处理逻辑");

80 }

81

82 }

83 }

用上面的方法会发现,在一次文本文件变化的时候OnChanged事件会触发两次,这是因为除了文本内容变化之外还有文件其他的属性也变化了例如修改时间。

为了解决这问题,也便于项目当中实际使用,写了下面几个类来实际使用:

主方法:
01 using System;

02 using System.IO;

03

04 namespace test

05 {

06 class Program

07 {

08 static void Main(string[] args)

09 {

10

11

12

13 MyFileSystemWather myWather = new MyFileSystemWather(@"C:\test", "*.txt");

14 myWather.OnChanged += new FileSystemEventHandler(OnChanged);

15 myWather.OnCreated += new FileSystemEventHandler(OnCreated);

16 myWather.OnRenamed += new RenamedEventHandler(OnRenamed);

17 myWather.OnDeleted += new FileSystemEventHandler(OnDeleted);

18 myWather.Start();

19 //由于是控制台程序,加个输入避免主线程执行完毕,看不到监控效果

20 Console.ReadKey();

21

22 }

23

24 private static void OnCreated(object source, FileSystemEventArgs e)

25 {

26

27 Console.WriteLine("文件新建事件处理逻辑");

28

29 }

30

31 private static void OnChanged(object source, FileSystemEventArgs e)

32 {

33

34 Console.WriteLine("文件改变事件处理逻辑");

35 }

36

37 private static void OnDeleted(object source, FileSystemEventArgs e)

38 {

39

40 Console.WriteLine("文件删除事件处理逻辑");

41 }

42

43 private static void OnRenamed(object source, RenamedEventArgs e)

44 {

45

46 Console.WriteLine("文件重命名事件处理逻辑");

47 }

48

49 }

50 }

WatcherProcess类:
01 using System.IO;

02

03 namespace test

04 {

05 public class WatcherProcess

06 {

07 private object sender;

08 private object eParam;

09

10 public event RenamedEventHandler OnRenamed;

11 public event FileSystemEventHandler OnChanged;

12 public event FileSystemEventHandler OnCreated;

13 public event FileSystemEventHandler OnDeleted;

14 public event Completed OnCompleted;

15

16 public WatcherProcess(object sender, object eParam)

17 {

18 this.sender = sender;

19 this.eParam = eParam;

20 }

21

22 public void Process()

23 {

24 if (eParam.GetType() == typeof(RenamedEventArgs))

25 {

26 OnRenamed(sender, (RenamedEventArgs)eParam);

27 OnCompleted(((RenamedEventArgs)eParam).FullPath);

28 }

29 else

30 {

31 FileSystemEventArgs e = (FileSystemEventArgs)eParam;

32 if (e.ChangeType == WatcherChangeTypes.Created)

33 {

34 OnCreated(sender, e);

35 OnCompleted(e.FullPath);

36 }

37 else if (e.ChangeType == WatcherChangeTypes.Changed)

38 {

39 OnChanged(sender, e);

40 OnCompleted(e.FullPath);

41 }

42 else if (e.ChangeType == WatcherChangeTypes.Deleted)

43 {

44 OnDeleted(sender, e);

45 OnCompleted(e.FullPath);

46 }

47 else

48 {

49 OnCompleted(e.FullPath);

50 }

51 }

52 }

53 }

54 }

MyFileSystemWather类:
001 using System;

002 using System.Collections;

003 using System.IO;

004 using System.Threading;

005

006 namespace test

007 {

008

009 public delegate void Completed(string key);

010

011 public class MyFileSystemWather

012 {

013 private FileSystemWatcher fsWather;

014

015 private Hashtable hstbWather;

016

017 public event RenamedEventHandler OnRenamed;

018 public event FileSystemEventHandler OnChanged;

019 public event FileSystemEventHandler OnCreated;

020 public event FileSystemEventHandler OnDeleted;

021

022 /// <summary>

023 /// 构造函数

024 /// </summary>

025 /// <param name="path">要监控的路径</param>

026 public MyFileSystemWather(string path, string filter)

027 {

028 if (!Directory.Exists(path))

029 {

030 throw new Exception("找不到路径:" + path);

031 }

032

033 hstbWather = new Hashtable();

034

035 fsWather = new FileSystemWatcher(path);

036 // 是否监控子目录

037 fsWather.IncludeSubdirectories = false;

038 fsWather.Filter = filter;

039 fsWather.Renamed += new RenamedEventHandler(fsWather_Renamed);

040 fsWather.Changed += new FileSystemEventHandler(fsWather_Changed);

041 fsWather.Created += new FileSystemEventHandler(fsWather_Created);

042 fsWather.Deleted += new FileSystemEventHandler(fsWather_Deleted);

043 }

044

045 /// <summary>

046 /// 开始监控

047 /// </summary>

048 public void Start()

049 {

050 fsWather.EnableRaisingEvents = true;

051 }

052

053 /// <summary>

054 /// 停止监控

055 /// </summary>

056 public void Stop()

057 {

058 fsWather.EnableRaisingEvents = false;

059 }

060

061 /// <summary>

062 /// filesystemWatcher 本身的事件通知处理过程

063 /// </summary>

064 /// <param name="sender"></param>

065 /// <param name="e"></param>

066 private void fsWather_Renamed(object sender, RenamedEventArgs e)

067 {

068 lock (hstbWather)

069 {

070 hstbWather.Add(e.FullPath, e);

071 }

072

073 WatcherProcess watcherProcess = new WatcherProcess(sender, e);

074 watcherProcess.OnCompleted += new Completed(WatcherProcess_OnCompleted);

075 watcherProcess.OnRenamed += new RenamedEventHandler(WatcherProcess_OnRenamed);

076 Thread thread = new Thread(watcherProcess.Process);

077 thread.Start();

078 }

079

080 private void WatcherProcess_OnRenamed(object sender, RenamedEventArgs e)

081 {

082 OnRenamed(sender, e);

083 }

084

085 private void fsWather_Created(object sender, FileSystemEventArgs e)

086 {

087 lock (hstbWather)

088 {

089 hstbWather.Add(e.FullPath, e);

090 }

091 WatcherProcess watcherProcess = new WatcherProcess(sender, e);

092 watcherProcess.OnCompleted += new Completed(WatcherProcess_OnCompleted);

093 watcherProcess.OnCreated += new FileSystemEventHandler(WatcherProcess_OnCreated);

094 Thread threadDeal = new Thread(watcherProcess.Process);

095 threadDeal.Start();

096 }

097

098 private void WatcherProcess_OnCreated(object sender, FileSystemEventArgs e)

099 {

100 OnCreated(sender, e);

101 }

102

103 private void fsWather_Deleted(object sender, FileSystemEventArgs e)

104 {

105 lock (hstbWather)

106 {

107 hstbWather.Add(e.FullPath, e);

108 }

109 WatcherProcess watcherProcess = new WatcherProcess(sender, e);

110 watcherProcess.OnCompleted += new Completed(WatcherProcess_OnCompleted);

111 watcherProcess.OnDeleted += new FileSystemEventHandler(WatcherProcess_OnDeleted);

112 Thread tdDeal = new Thread(watcherProcess.Process);

113 tdDeal.Start();

114 }

115

116 private void WatcherProcess_OnDeleted(object sender, FileSystemEventArgs e)

117 {

118 OnDeleted(sender, e);

119 }

120

121 private void fsWather_Changed(object sender, FileSystemEventArgs e)

122 {

123 if (e.ChangeType == WatcherChangeTypes.Changed)

124 {

125 if (hstbWather.ContainsKey(e.FullPath))

126 {

127 WatcherChangeTypes oldType = ((FileSystemEventArgs)hstbWather[e.FullPath]).ChangeType;

128 if (oldType == WatcherChangeTypes.Created || oldType == WatcherChangeTypes.Changed)

129 {

130 return;

131 }

132 }

133 }

134

135 lock (hstbWather)

136 {

137 hstbWather.Add(e.FullPath, e);

138 }

139 WatcherProcess watcherProcess = new WatcherProcess(sender, e);

140 watcherProcess.OnCompleted += new Completed(WatcherProcess_OnCompleted);

141 watcherProcess.OnChanged += new FileSystemEventHandler(WatcherProcess_OnChanged);

142 Thread thread = new Thread(watcherProcess.Process);

143 thread.Start();

144 }

145

146 private void WatcherProcess_OnChanged(object sender, FileSystemEventArgs e)

147 {

148 OnChanged(sender, e);

149 }

150

151 public void WatcherProcess_OnCompleted(string key)

152 {

153 lock (hstbWather)

154 {

155 hstbWather.Remove(key);

156 }

157 }

158 }

159 }

使
用了线程安全的Hashtable来处理一次改变触发两次事件的问题,要注意的是在实际项目使用中,在通过监控文件事情触发时开一个线程
WatcherProcess去处理自己业务逻辑的时候,不管业务逻辑成功或者失败(例如有异常抛出一定要try一下)一定要让
WatcherProcess的
Completed也就是MyFileSystemWather的WatcherProcess_OnCompleted执行去移除对应变化文件的
Hashtable的key,不然下次此文件改变时是无法触发你的业务逻辑的。

还有就是在进行文件监控的时候, 被监控文件在写入的时候,是会有I/O冲突的,即使写入文件是FileShare.Read的也会出现,要真正解决貌似只有FileMaping方法,但是我的项目中文本的写入软件不是我们能控制的,所以只有用处理异常的方法来解决。

在C#使用文件监控对象FileSystemWatcher的几种方案的更多相关文章

  1. 使用文件监控对象FileSystemWatcher实现数据同步

    最近在项目中有这么个需求,就是得去实时获取某个在无规律改变的文本文件中的内容.首先想到的是用程序定期去访问这个文件,因为对实时性要求很高,间隔不能超过1S,而且每次获取到文本内容都要去分发给WEB服务 ...

  2. C#使用文件监控对象FileSystemWatcher 实现数据同步

    在C#使用文件监控对象FileSystemWatcher 实现数据同步 2013-12-12 18:24 by 幕三少, 352 阅读, 3 评论, 收藏, 编辑 最近在项目中有这么个需求,就是得去实 ...

  3. 在C#使用文件监控对象FileSystemWatcher 实现数据同步

    最近在项目中有这么个需求,就是得去实时获取某个在无规律改变的文本文件中的内容.首先想到的是用程序定期去访问这个文件,因为对实时性要求很高,间隔不能超过1S,而且每次获取到文本内容都要去分发给WEB服务 ...

  4. C#文件监控对象FileSystemWatcher实例,通过监控文件创建、修改、删除、重命名对服务器数据进行实时备份

    先上图,简单的windorm界面:此为最初的版本,后续会增加监听多个源目录的功能.log功能.进度条展示功能等. 1.初始化监听 /// <summary> /// 初始化监听 /// & ...

  5. 文件监控只FileSystemWatcher控件

    FileSYstemWatcher控件是用来监控一个文件系统或监控文件变化.该控件会通知文件创建.修改.删除的消息,分别通过Created事件.Changed事件和Deleted事件来处理对应的操作 ...

  6. C#使用FileSystemWatcher控件实现的文件监控功能示例

    本文实例讲述了C#使用FileSystemWatcher控件实现的文件监控功能.分享给大家供大家参考,具体如下: FileSystemWatcher 可以使用FileSystemWatcher组件监视 ...

  7. 超实用文件监控多线程FTP上传工具

    这是自己很久以前写的一个多线程FTP 上传工具,支持多账户,自定义线程数,自定义文件监控目录,可用做文件发布使用,非常实用,今天有小伙伴问起,现分享出来: using System; using Sy ...

  8. Prometheus基于consul自动发现监控对象 https://www.iloxp.com/archive/11/

      Prometheus 监控目标为什么要自动发现 频繁对Prometheus配置文件进行修改,无疑给运维人员带来很大的负担,还有可能直接变成一个“配置小王子”,即使是配置小王子也会存在人为失误的情况 ...

  9. Emit动态生成代理类用于监控对象的字段修改

    利用Emit动态生成代理对象监控对象哪些字段被修改,被修改为什么值 被Register的对象要监控的值必须是Virtual虚类型 必须使用CreateInstance创建对象 必须使用DynamicP ...

随机推荐

  1. JS实现电子时钟

          目前有个小项目,在首页头部导航栏里需要一个电子时钟的效果,于是我就采用如下代码实现了一个电子时钟的效果.不过不完美,第一种方式容易导致网页莫名其妙的异常,后来觉得可能是做的操作太多了,然后 ...

  2. CODEVS1291 火车线路

    http://codevs.cn/problem/1291/ 题目描述 Description 某列火车行使在C个城市之间(出发的城市编号为1,结束达到的城市的编号为C),假设该列火车有S个座位,现在 ...

  3. 洛谷P2728 纺车的轮子 Spinning Wheels

     P2728 纺车的轮子 Spinning Wheels 29通过 66提交 题目提供者该用户不存在 标签USACO 难度普及/提高- 提交  讨论  题解 最新讨论 暂时没有讨论 题目背景 一架纺车 ...

  4. [设计模式 3] 用设计模式的眼光看MVC框架

    导读:之前一直在区分MVC和设计模式的区别,但是,既然有些人认为MVC是一种设计模式,那么它们之间肯定是有共通之处的.所以,本篇博客,就用设计模式的眼光来看MVC框架.仅是本人对于MVC的粗鄙看法,还 ...

  5. C++ Namespace 详解

    命名空间的定义格式为:(取自C++标准文档) named-namespace-definition: namespace identifier { namespace-body } unnamed-n ...

  6. asp.net ashx 一般处理程序 使用async await异步直接 copy可用哦

    以前一直很懒  碰到ashx要用await异步就绕开  用aspx  或者mvc异步控制器  这次公司需要  我查了国内的文章基本都不能简单copy来处理一堆错关键的过程中函数BeginProcess ...

  7. 【.NET】MD5的用法(对文件、字符串)

    using System;using System.IO;using System.Security.Cryptography;using System.Text;namespace ConsoleA ...

  8. Linux之文件系统的简单操作

    df:列出文件系统整体硬盘使用量 将容量以易读方式显示: [root@zkero ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/s ...

  9. css初涉

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. MBR解析

    先推广一下QQ群:61618925.欢迎各位爱好编程的朋友加入. 一.程序界面 二.关键部分代码: 1.数据结构定义 #define MBRSIZE 512 #define BOOTRECORDSIZ ...