谈谈C#文件监控对象FileSystemWatcher使用感受

2017年07月07日 14:52:32 savagelin 阅读数:3530

最近在项目中有这么个需求,就是得去实时获取某个在无规律改变的文本文件中的内容。首先想到的是用程序定期去访问这个文件,因为对实时性要求很高,间隔不能超过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的基本知识,大部分是从网上搜找的然后自己稍微整理了一下。

下面为简单用法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

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("文件重命名事件处理逻辑");

        }

    }

}

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

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

主方法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

using System;

using System.IO;

namespace test

{

    class Program

    {

        static void Main(string[] args)

        {

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

            myWather.OnChanged += new FileSystemEventHandler(OnChanged);

            myWather.OnCreated += new FileSystemEventHandler(OnCreated);

            myWather.OnRenamed += new RenamedEventHandler(OnRenamed);

            myWather.OnDeleted += new FileSystemEventHandler(OnDeleted);

            myWather.Start();

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

            Console.ReadKey();

        }

        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("文件重命名事件处理逻辑");

        }

    }

}

WatcherProcess类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

using System.IO;

namespace test

{

    public class WatcherProcess

    {

        private object sender;

        private object eParam;

        public event RenamedEventHandler OnRenamed;

        public event FileSystemEventHandler OnChanged;

        public event FileSystemEventHandler OnCreated;

        public event FileSystemEventHandler OnDeleted;

        public event Completed OnCompleted;

        public WatcherProcess(object sender, object eParam)

        {

            this.sender = sender;

            this.eParam = eParam;

        }

        public void Process()

        {

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

            {

                OnRenamed(sender, (RenamedEventArgs)eParam);

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

            }

            else

            {

                FileSystemEventArgs e = (FileSystemEventArgs)eParam;

                if (e.ChangeType == WatcherChangeTypes.Created)

                {

                    OnCreated(sender, e);

                    OnCompleted(e.FullPath);

                }

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

                {

                    OnChanged(sender, e);

                    OnCompleted(e.FullPath);

                }

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

                {

                    OnDeleted(sender, e);

                    OnCompleted(e.FullPath);

                }

                else

                {

                    OnCompleted(e.FullPath);

                }

            }

        }

    }

}

MyFileSystemWather类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

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);

            }

        }

    }

}

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

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

轉自:http://www.cnblogs.com/zhaojingjing/archive/2011/01/21/1941586.html

谈谈C#文件监控对象FileSystemWatcher使用感受相关推荐

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

    使用文件监控对象FileSystemWatcher实现数据同步 原文 使用文件监控对象FileSystemWatcher实现数据同步 最近在项目中有这么个需求,就是得去实时获取某个在无规律改变的文本文 ...

  2. 详解C#使用FileSystemWatcher文件监控对象的感受

    ** 详解C#使用FileSystemWatcher文件监控对象的感受 ** 本文和大家一起来学习分享一下C#使用FileSystemWatcher文件监控对象,希望对你有帮助. 最近在项目中有这么个 ...

  3. 文件监控之FileSystemWatcher(c++)

    文件监控之FileSystemWatcher(c++) 为了监控web程序的静态文件是否被恶意改动,所以学习了一下FileSystemWatcher  类对文件的监控,由于还在初级阶段,这里只贴一下关 ...

  4. [VB.NET]文件观察对象FileSystemWatcher

    转载于:https://www.cnblogs.com/lizunicon/archive/2008/07/11/1240784.html

  5. C# FileSystemWatcher文件监控

    对于一个需要管理本地文件的应用来说,监控文件的运行及修改状态十分重要,在运行中,我们如何知道文件的基本属性的变化? C#为我们提供了一个文件监控类(FileSystemWatcher),它定义了几个文 ...

  6. C# FileSystemWatcher 多文件夹、多文件类型文件监控增加、修改、重命名和删除实例

    在上一次讲过了FileSystemWatcher 实时监控文件的增加.修改.重命名和删除,具体怎么实现就不再去阐述,参考如下文 C# FileSystemWatcher 实时监控文件的增加.修改.重命 ...

  7. 文件监控——watchdog详解

    文章目录 文件监控--watchdog详解 一.官方文档(需要细节选择去官网,需要了解和应用范例看本文即可) 二.watchdog安装 1. Installing from PyPI using pi ...

  8. nagios2------添加监控对象

    ① 监控对象 ② 配置选项 ③ 报警选项 ================================= 定义监控对象 nagios.cfg # vi nagios.cfg # mkdir ser ...

  9. python watchdog 同时检测到多个事件_python中watchdog文件监控与检测上传功能

    引言 上一篇介绍完了观察者模式的原理,本篇想就此再介绍一个小应用,虽然我也就玩了一下午,是当时看observer正好找到的,以及还有Django-observer,但Django很久没用了,所以提下这 ...

最新文章

  1. 【Java】全站编码过滤器GenericEncodingFilter代码与配置
  2. 【数据结构笔记】B树和B+树的实现,哈希查找,STL中的hash_map和unordered_map容器用法
  3. C#6.0中$的用法
  4. E. Jamie and Tree(树链剖分 + 线段树)
  5. qt添加资源文件后编译失败,提示Qt:Error:No rule to make target ’ … /…/??.png’,needed by ‘debug/qrc_qrc.cpp’ stop
  6. python远程主机强迫关闭了_Python 远程主机强迫关闭了一个现有的连接
  7. python svm向量_支持向量机(SVM)及其Python实现
  8. 快速查找对方IP经典技巧汇总
  9. 仿王者荣耀HTML示例代码
  10. mysql distance_MySql中的一些小坑
  11. Android面试Hash原理详解二
  12. 《SQL必知必会》学习笔记——第十二课 连结表
  13. VOT 2015 Benchmark 使用教程
  14. ABAP:增强篇-MIGO过账增强之CHECK方法获取行项目
  15. 软件工程作业-——项目设计
  16. 新手如何做跨境电商?这七个经验干货请收好!
  17. 三十二楼层选几层最好_一般买房买几楼比较好 1一32高楼层选最佳楼层
  18. C#线程操作UI控件
  19. eventlet并发读写socket出现Second simultaneous问题
  20. 密码学09-数字签名

热门文章

  1. Oracle SQL 调优健康检查脚本
  2. 从深度心理学的角度看爱情(强烈推荐)
  3. 美国知名投行摩根大通警告,史上最大的美股泡沫或在明年破灭
  4. win7插了耳机还是外放_地铁禁止外放10天后,我的耳朵还是阵亡了
  5. selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable: [obje
  6. wget连接指定端口_wget使用方法
  7. 如何保存计算机重要文档,电脑里的重要文件怎样保存才安全?
  8. bond4 交换机配置_网卡bonding模式 - bond0、1、4配置
  9. UML图及软件设计原则详解
  10. 多米诺骨牌效应,量子计算机大规模扩展的新途径