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

(转)

最近要用到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
FileSystemWatcher component generates not only
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 plaincopy

  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. }

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

时间: 2024-10-08 23:11:55

FileSystemWatcher触发多次Change事件的解决办法的相关文章

FileSystemWatcher触发多次Change事件的解决办法转族坐锥茁篆

http://www.ebay.com/cln/rbx_lddh/2015-01-30/166703156014 http://www.ebay.com/cln/3f7_jhpv/2015-01-30/166703167014 http://www.ebay.com/cln/dt3_njjv/2015-01-30/166882325011 http://www.ebay.com/cln/57t_rvrj/2015-01-30/166838006016 http://www.ebay.com/cl

双击事件失效解决办法

某些时候,双击事件会失效,模拟办法解决双击失效后,而同时我又不想在该元素上触发两次单击事件,解决办法如下: var dbclickTime={ prev:0, next:0//模拟触发双击};var clickConflict={//解决单击事件和双击事件的冲突 _timeout:null, set:function (fn) { this.clear(); this._timeout=window.setTimeout(fn,400); }, clear:function () { if(th

js设置下拉框选中后change事件无效解决

下拉框部分代码: <select id="bigType"> <option value="">请选择</option> <option value="1">xiamen</option> <option value="2">beijing</option> </select> <select id="smallTy

[Phonegap+Sencha Touch] 移动开发16 安卓webview中,input输入框不触发backspace回退键事件的解决办法

可以用安卓手机浏览器打开 http://javascript.info/tutorial/keyboard-events#test-stand-test-stand 测试看看. Android 4.2自带浏览器和webview的测试结果(其他版本没试过,估计4.X都是这样): 当input有内容的时候,点击软键盘回退键(keyCode=8),是有keyEvents事件(keyup keydown)触发的:当input是空的时候,再点击,就不触发keyEvents了. Chrome浏览器测试结果:

jquery 怎么触发select的change事件

可以使用jQuery的trigger() 方法来响应事件 定义和用法 trigger() 方法触发被选元素的指定事件类型. 语法 $(selector).trigger(event,[param1,param2,...]) 参数描述 event    必需.规定指定元素要触发的事件.可以使自定义事件(使用 bind() 函数来附加),或者任何标准事件. [param1,param2,...]    可选.传递到事件处理程序的额外参数.额外的参数对自定义事件特别有用. 实例: 触发 select元

JS事件冒泡解决办法

<div id="div1"> <div id="div2"> <input type="button" value="按钮"/> </div> </div> $(function(){ $("div1").click(function(){ alert("DIV1"); }); $("div2").clic

append()方法生成的元素绑定的事件失效解决办法

我使用append()方法动态生成的a链接的click事件没有起效果,查找了资料,了解到,我使用的onclick方法绑定的事件对动态生成的元素是无效的,解决办法如下: 使用事件委托,并且要用on来绑定未来事件: $(父节点).on("事件","目标节点",function(){}) 我这里的例子是: $('#com').on("click",".comment",function(e){}) 问题解决了.

js改变select的选中项不触发select的change事件

// test var selectEl = document.querySelector('select') var buttonEl = document.querySelector('button') selectEl.addEventListener('change', function() { console.log(this.value) }) buttonEl.addEventListener('click', function() { selectEl.options[1].se

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

参考: http://www.cnblogs.com/xcsn/p/3413074.html http://www.soso.io/article/21182.html 最近做一个输入框只能输入有两位小数点的小数,当时监听的是keyup事件,当输入法改为中文,然后按enter键,这样还是能输入其他的字符(火狐没有这个问题,谷歌里有这个问题),后来百度下才知道原因,具体参考以上两个网址. 修改前写法: <input type="text" name="inputorp_i