最近要用到FileSystemWatcher来监控某个目录中的文件是否发生改变,如果改变就执行相应的操作。但在开发过程中,发现FileSystemWatcher在文件创建或修改后,会触发多个Created或Changed事件,具体原因就是处理文件的过程中执行了多次文件系统操作,触发了多次事件。具体可以参看微软的关于FileSystemWatcher这方面的解释:Troubleshooting FileSystemWatcher Components ,另外我在网上发现 Consolidate Multiple FileSystemWatcher Events 关于这方面的解决办法,比较实用,方便快速引入到项目中。

来自MSDN的问题说明

Troubleshooting FileSystemWatcher Components

Visual Studio .NET 2003
其他版本

此主题尚未评级 - 评价此主题

You may encounter the following situations while working with the FileSystemWatcher component:

UNC Path Names Not Accepted on Windows NT 4.0 Computers

If you are working with a FileSystemWatcher component on a Windows NT version 4.0 computer and trying to set its path to monitor file system activity on a different Windows NT version 4.0 computer, you will not be able to specify a UNC-based path value in the Path property to point to the computer in question. You can only set UNC-based values when working on Windows 2000 computers.

Cannot Watch Windows 95 or Windows 98 Directories

If you set your FileSystemWatcher component to reference a directory on a Windows 95 or Windows 98 computer, you will receive an error about an invalid directory path when the project runs. When using FileSystemWatcher, you cannot watch directories on computers running Windows 95 or Windows 98.

Multiple Created Events Generated for a Single Action

You may notice in certain situations that a single creation event generates multiple Created events that are handled by your component. For example, if you use aFileSystemWatcher component to monitor the creation of new files in a directory, and then test it by using Notepad to create a file, you may see two Created events generated even though only a single file was created. This is because Notepad performs multiple file system actions during the writing process. Notepad writes to the disk in batches that create the content of the file and then the file attributes. Other applications may perform in the same manner. Because FileSystemWatcher monitors the operating system activities, all events that these applications fire will be picked up.

Note   Notepad may also cause other interesting event generations. For example, if you use the ChangeEventFilter to specify that you want to watch only for attribute changes, and then you write to a file in the directory you are watching using Notepad, you will raise an event . This is because Notepad updates theArchived attribute for the file during this operation.

Unexpected Events Generated on Directories

Changing a file within a directory you are monitoring with a FileSystemWatcher component generates not only a Changed event on the file but also a similar event for the directory itself. This is because the directory maintains several types of information for each file it contains — the names and sizes of files, their modification dates, attributes, and so on. Whenever one of these attributes changes, a change is associated with the directory as well.

解决方案

The .NET framework provides a FileSystemWatcher class that can be used to monitor the file system for changes. My requirements were to monitor a directory for new files or changes to existing files. When a change occurs, the application needs to read the file and immediately perform some operation based on the contents of the file.

While doing some manual testing of my initial implementation it was very obvious that theFileSystemWatcher was firing multiple events whenever I made a change to a file or copied a file into the directory being monitored. I came across the following in the MSDNdocumentation’s Troubleshooting FileSystemWatcher Components

Multiple Created Events Generated for a Single Action

You may notice in certain situations that a single creation event generates multiple Created events that are handled by your component. For example, if you use a FileSystemWatcher component to monitor the creation of new files in a directory, and then test it by using Notepad to create a file, you may see two Created events generated even though only a single file was created. This is because Notepad performs multiple file system actions during the writing process. Notepad writes to the disk in batches that create the content of the file and then the file attributes. Other applications may perform in the same manner. Because FileSystemWatcher monitors the operating system activities, all events that these applications fire will be picked up.

Note: Notepad may also cause other interesting event generations. For example, if you use the ChangeEventFilter to specify that you want to watch only for attribute changes, and then you write to a file in the directory you are watching using Notepad, you will raise an event. This is because Notepad updates the Archived attribute for the file during this operation.

I did some searching and was surprised that .NET did not provide any kind of wrapper around the FileSystemWatcher to make it a bit more user friendly. I ended up writing my own wrapper that would monitor a directory and only throw one event when a new file was created, or an existing file was changed.

In order to consolidate the multiple FileSystemWatcher events down to a single event, I save the timestamp when each event is received, and I check back every so often (using a Timer) to find paths that have not caused additional events in a while. When one of these paths is ready, a single Changed event is fired. An additional benefit of this technique is that the event from the FileSystemWatcher is handled very quickly, which could help prevent its internal buffer from filling up.

Here is the code for a DirectoryMonitor class that consolidates multiple Win32 events into a single Change event for each change:

解决方案代码

[csharp] view plaincopyprint?
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. using System.Threading;
  7. namespace ShareReadFile
  8. {
  9. public delegate void FileSystemEvent(String path);
  10. public interface IDirectoryMonitor
  11. {
  12. event FileSystemEvent Change;
  13. void Start();
  14. }
  15. public class DirectoryMonitor : IDirectoryMonitor
  16. {
  17. private readonly FileSystemWatcher m_fileSystemWatcher = new FileSystemWatcher();
  18. private readonly Dictionary<string, DateTime> m_pendingEvents = new Dictionary<string, DateTime>();
  19. private readonly Timer m_timer;
  20. private bool m_timerStarted = false;
  21. public DirectoryMonitor(string dirPath)
  22. {
  23. m_fileSystemWatcher.Path = dirPath;
  24. m_fileSystemWatcher.IncludeSubdirectories = false;
  25. m_fileSystemWatcher.Created += new FileSystemEventHandler(OnChange);
  26. m_fileSystemWatcher.Changed += new FileSystemEventHandler(OnChange);
  27. m_timer = new Timer(OnTimeout, null, Timeout.Infinite, Timeout.Infinite);
  28. }
  29. public event FileSystemEvent Change;
  30. public void Start()
  31. {
  32. m_fileSystemWatcher.EnableRaisingEvents = true;
  33. }
  34. private void OnChange(object sender, FileSystemEventArgs e)
  35. {
  36. // Don't want other threads messing with the pending events right now
  37. lock (m_pendingEvents)
  38. {
  39. // Save a timestamp for the most recent event for this path
  40. m_pendingEvents[e.FullPath] = DateTime.Now;
  41. // Start a timer if not already started
  42. if (!m_timerStarted)
  43. {
  44. m_timer.Change(100, 100);
  45. m_timerStarted = true;
  46. }
  47. }
  48. }
  49. private void OnTimeout(object state)
  50. {
  51. List<string> paths;
  52. // Don't want other threads messing with the pending events right now
  53. lock (m_pendingEvents)
  54. {
  55. // Get a list of all paths that should have events thrown
  56. paths = FindReadyPaths(m_pendingEvents);
  57. // Remove paths that are going to be used now
  58. paths.ForEach(delegate(string path)
  59. {
  60. m_pendingEvents.Remove(path);
  61. });
  62. // Stop the timer if there are no more events pending
  63. if (m_pendingEvents.Count == 0)
  64. {
  65. m_timer.Change(Timeout.Infinite, Timeout.Infinite);
  66. m_timerStarted = false;
  67. }
  68. }
  69. // Fire an event for each path that has changed
  70. paths.ForEach(delegate(string path)
  71. {
  72. FireEvent(path);
  73. });
  74. }
  75. private List<string> FindReadyPaths(Dictionary<string, DateTime> events)
  76. {
  77. List<string> results = new List<string>();
  78. DateTime now = DateTime.Now;
  79. foreach (KeyValuePair<string, DateTime> entry in events)
  80. {
  81. // If the path has not received a new event in the last 75ms
  82. // an event for the path should be fired
  83. double diff = now.Subtract(entry.Value).TotalMilliseconds;
  84. if (diff >= 75)
  85. {
  86. results.Add(entry.Key);
  87. }
  88. }
  89. return results;
  90. }
  91. private void FireEvent(string path)
  92. {
  93. FileSystemEvent evt = Change;
  94. if (evt != null)
  95. {
  96. evt(path);
  97. }
  98. }
  99. }
  100. }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;namespace ShareReadFile
{public delegate void FileSystemEvent(String path);public interface IDirectoryMonitor{event FileSystemEvent Change;void Start();}public class DirectoryMonitor : IDirectoryMonitor{private readonly FileSystemWatcher m_fileSystemWatcher = new FileSystemWatcher();private readonly Dictionary<string, DateTime> m_pendingEvents = new Dictionary<string, DateTime>();private readonly Timer m_timer;private bool m_timerStarted = false;public DirectoryMonitor(string dirPath){m_fileSystemWatcher.Path = dirPath;m_fileSystemWatcher.IncludeSubdirectories = false;m_fileSystemWatcher.Created += new FileSystemEventHandler(OnChange);m_fileSystemWatcher.Changed += new FileSystemEventHandler(OnChange);m_timer = new Timer(OnTimeout, null, Timeout.Infinite, Timeout.Infinite);}public event FileSystemEvent Change;public void Start(){m_fileSystemWatcher.EnableRaisingEvents = true;}private void OnChange(object sender, FileSystemEventArgs e){// Don't want other threads messing with the pending events right nowlock (m_pendingEvents){// Save a timestamp for the most recent event for this pathm_pendingEvents[e.FullPath] = DateTime.Now;// Start a timer if not already startedif (!m_timerStarted){m_timer.Change(100, 100);m_timerStarted = true;}}}private void OnTimeout(object state){List<string> paths;// Don't want other threads messing with the pending events right nowlock (m_pendingEvents){// Get a list of all paths that should have events thrownpaths = FindReadyPaths(m_pendingEvents);// Remove paths that are going to be used nowpaths.ForEach(delegate(string path){m_pendingEvents.Remove(path);});// Stop the timer if there are no more events pendingif (m_pendingEvents.Count == 0){m_timer.Change(Timeout.Infinite, Timeout.Infinite);m_timerStarted = false;}}// Fire an event for each path that has changedpaths.ForEach(delegate(string path){FireEvent(path);});}private List<string> FindReadyPaths(Dictionary<string, DateTime> events){List<string> results = new List<string>();DateTime now = DateTime.Now;foreach (KeyValuePair<string, DateTime> entry in events){// If the path has not received a new event in the last 75ms// an event for the path should be fireddouble diff = now.Subtract(entry.Value).TotalMilliseconds;if (diff >= 75){results.Add(entry.Key);}}return results;}private void FireEvent(string path){FileSystemEvent evt = Change;if (evt != null){evt(path);}}}
}

转载于:https://www.cnblogs.com/amylis_chen/p/3293803.html

FileSystemWatcher触发多次Change事件的解决办法 .相关推荐

  1. FileSystemWatcher触发多次Change事件的解决办法

    最近要用到FileSystemWatcher来监控某个目录中的文件是否发生改变,如果改变就执行相应的操作.但在开发过程中,发现FileSystemWatcher在文件创建或修改后,会触发多个Creat ...

  2. java textvaluechanged 全选删除不触发_js动态改变input的值不触发input的change事件的解决办法...

    看了网上的资料也比较杂,自己也做一个整理共享一下解决方案 1.原生js的改变之后手动添加监听 1 2 3 var ttt = document.getElementById("ttt&quo ...

  3. 在layui中使用 jquery 触发select 的 change事件无效

    在layui中使用 jquery 触发select 的 change事件无效 使用layui.use监听select事件 <select lay-filter="demo" ...

  4. 中文输入法不触发onkeyup事件的解决办法

    2019独角兽企业重金招聘Python工程师标准>>> 这两天做一个需要实时监控文本框输入的功能,碰到了中文输入法无法触发onkeyup事件的恶心问题. 具体表现是这样的: 当监听一 ...

  5. 【JQuery】 触发元素的change事件

    select元素的change事件 通过修改select元素的值($("#select_id").val("new value"))并不会触发change事件. ...

  6. Android Activity使用OnGesture事件以后与子View的Click事件冲突解决办法

    在实现多个图片的切换功能时,使用到了手势事件功能,但同时需要给图片增加一个单击事件去执行其它功能.增加单击事件后,图片会截取到touchdown并不再往下传递,导致手势事件失效,这里给出了其解决办法, ...

  7. IE下列表框不能给option绑定click事件的解决办法

    列表框代码 <select size="3" ><option>Option1</option><option>Option2< ...

  8. vs提示出现“xxx.exe中已触发了一个断点”错误的解决办法

    当vs在运行代码结束后出现"xxx.exe中已触发了一个断点"这样的报错后,最主要的原因应该是内存管理出现了问题,野指针.溢出等等. 在今天的代码调试中就出现了这样的问题 并且伴随 ...

  9. c#的FileSystemWatcher对象监视文件的变化的事件,无休止的触发事件的解决办法

    FileSystemWatcher.Changed 事件 中又修改文件时 会发生死循环 原因是:程序收到文件发生更改的通知后,马上又修改了文件,从而又使文件产生了更改的通知 static void w ...

最新文章

  1. linux中tomcat修改错误日志路径
  2. FirstApp,iphone开发学习总结7,相机
  3. 【PP操作手册】生产订单的查询
  4. Mybatis_映射文件配置
  5. Dubbo——Dubbo协议整合Jackson序列化解决方案
  6. python 手机测试_python脚本如何测试手机
  7. .NET 机器学习生态调查
  8. linux中使用yum的优点,linux – 自动“yum update”以保证服务器安全 – 优点和缺点?...
  9. location.replace与location.href,location.reload的区别
  10. 《C++标准库》笔记--STL 2
  11. 【hdu 4859】海岸线(图论--网络流最小割)
  12. sed 去掉最后一行_shell sed命令匹配替换删除最后第一行字符正则表
  13. windows下的csrss.exe进程
  14. 报错Found existing installation: tensorflow 1.2.1
  15. oracle edmx,EDMX实体框架
  16. 联想笔记本e43l_联想昭阳e43l
  17. Android 百度地图反向Geo “PERMISSION UNFINISHED“
  18. 1/cos(x)、1/sin(x)的不定积分推导
  19. java 通用权限管理_通用权限管理设计篇(一)
  20. Python之Pickle学习

热门文章

  1. 360创始人周鸿祎曾这样告诫年轻人
  2. 现在资本进入社区团购,大搞补贴战,算不算涉嫌扰乱市场,垄断?
  3. 未来几十年替代手机的是什么产品?
  4. iOS系统什么天气app可以访问锁屏?
  5. iPhone11用第三方的快充,电池健康度会下降很快吗?
  6. In the beginning, many people on Wall Street did
  7. OpenCV绘制线、矩形、圆等基本几何形状
  8. rdlc tablix_SQL Server中的报表–通过分组功能(由Tablix控件提供)处理数据
  9. ssis 执行任务的日志_SSIS和PowerShell –执行流程任务
  10. 数据库mdf和ldf文件_如何将SQL数据库文件(MDF和LDF)移动到另一个位置