VB.NET FileSystemWatcher 多个更改事件
我有以下代码:
Imports System.IO
Public Class Blah
Public Sub New()
InitializeComponent()
Dim watcher As New FileSystemWatcher("C:\")
watcher.EnableRaisingEvents = True
AddHandler watcher.Changed, AddressOf watcher_Changed
End Sub
Private Sub watcher_Changed(ByVal sender As Object, ByVal e As FileSystemEventArgs)
MsgBox(e.FullPath)
End Sub
End Class
当我运行它并将更改保存到 C 驱动器上的文件时,代码运行良好,只是它执行了 watcher_Changed() 方法四次。 知道为什么吗? 每次的changeType都是“4”。
谢谢。
I have the following code:
Imports System.IO
Public Class Blah
Public Sub New()
InitializeComponent()
Dim watcher As New FileSystemWatcher("C:\")
watcher.EnableRaisingEvents = True
AddHandler watcher.Changed, AddressOf watcher_Changed
End Sub
Private Sub watcher_Changed(ByVal sender As Object, ByVal e As FileSystemEventArgs)
MsgBox(e.FullPath)
End Sub
End Class
When I run it and save changes to a file on my C drive, the code works great, except it executes the watcher_Changed() method four times. Any idea why? The changeType is "4" every time.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
来自 VS.NET 文档的“FileSystemWatcher 组件故障排除”部分...
From the "Troubleshooting FileSystemWatcher Components" section of the VS.NET documentation...
不久前,我也遇到了同样的问题。
经过一番网络搜索后,看来我并不是唯一一个遇到这个问题的人。 :)
所以,也许这是 FileSystemWatcher 中的一个缺陷......
我已经通过跟踪上次引发事件处理程序的时间来解决它。 如果它是在 xxx 毫秒前引发的,我会从事件处理程序中返回。
如果有人知道更优雅的修复方法; 请告诉我。 :)
这就是我解决这个问题的方法:
A while ago, I've experience the same problem.
After some searching thtrough the web, it appeared that I was not the only one having this issue. :)
So, perhaps it is a flaw in the FileSystemWatcher ...
I've solved it by keeping track of the last time the eventhandler has been raised. If it has been raised less then xxx msec ago, I return from my eventhandler.
If anyone knows a fix that is more elegant; plz let me know. :)
This is how I've worked around it:
Frederik 的解决方案是迄今为止我遇到的最好的解决方案。 然而我发现 500 毫秒太慢了。 在我的应用程序中,用户能够在 0.5 秒内轻松地对文件执行两个操作,因此我将其降低到 100,到目前为止效果很好。 他的 C# 有点 fubar(它不会转换),所以这是 VB 版本:
Frederik's solution is by the far the best thing I've come across. However I found 500 milliseconds to be far too slow. In my app a user is able to perform two actions on a file easily within .5 seconds so I lowered it to 100 and so far it's working out fine. His C# was a little fubar (it wouldn't convert) so here's the VB version:
我对这个问题的解决方案有点像 Erics,除了我使用 System.Windows.Forms.Timer 而不是启动新线程。 我的想法是,仅当 x 毫秒过去且没有任何文件更改事件时才处理更改事件。 请注意,一切都发生在 GUI 线程上,因此不存在线程问题。 我使用 x = 100。
My solution to this problem is a bit like Erics except I use a System.Windows.Forms.Timer in stead of starting a new thread. The idea is that I handle the change event only when x ms have passed without any file changed events. Note that everything takes place on the GUI thread so there are no threading issues. I use x = 100.
观察者更改事件处理程序将触发 3 个事件...创建、删除、更改。 仅当您重命名文件时,才会触发 onrenamed 事件。 这可能就是您收到 4 个警报的原因。
此外,大多数程序在关闭文件之前会对文件运行多个操作。 每个事件都被视为更改,因此每次都会触发 on_changed 事件。
the watcher changed event handler will fire on 3 events... create, delete,change. Only when you rename a file will the onrenamed event fire. That is probably why you are getting 4 alerts.
Also most programs run multiple operations on a file before closing it. Every event is considered a change and so the on_changed event is fired every time.
假设每次路径都相同,您用来保存文件的程序是否可能实际上是分段保存的? 或者您是否实例化了多个
Blah
?编辑:
您是否正在运行任何防病毒自动保护软件? 这些可能会在此过程中接触文件。
来自 MSDN 文档:
编辑:或者也许与 Windows 保存文件的方式有关。 您可能会从不同的更改中获得多个事件。 (一个用于大小,一个用于上次写入时间戳,一个用于上次访问时间戳,还有一个用于...其他内容。)尝试设置
FileSystemWatcher
的NotifyFilter 属性更改为单一类型并查看是否继续获取多个事件。
Assuming the path is the same every time, is it possible the program you are using to save the file is actually doing the save in pieces? Or do you have more than one
Blah
instantiated?Edit:
Do you have any antivirus auto-protect software running? Those might be touching the file in the process.
From the MSDN Documentation:
Edit: Or maybe there's something to do with how windows is saving the file. You might be getting more than one event from different changes. (One for the size, one for the last write timestamp, one for the last access timestamp, and one more for...something else.) Try setting the
FileSystemWatcher
'sNotifyFilter
property to a single type of change and see if you continue to get multiple events.还有另一种可能性,你犯了错误:)
也许您在将“Blah”类用于文件监视目的之前实例化并终止它,并且忘记通过 Dispose/或任何相关的拆卸方法来实现RemoveHandler。 (?)
There is another possibility, which you are making mistake :)
Maybe you are instantiate and terminate your "Blah" class before using it for filewatching purpose, and forgetting to implement RemoveHandler by Dispose/or any related teardown method. (?)
我编写了一些代码来解决这个问题以及 FileSystemWatcher 的其他巧妙功能。 它发布在我的博客中: http:// precisionsoftware.blogspot.com /2009/05/filesystemwatcher-done-right.html
I wrote some code that solves this problem and other neat features of FileSystemWatcher. Its posted in my blog at: http://precisionsoftware.blogspot.com/2009/05/filesystemwatcher-done-right.html
我找到了这个页面来解决同样的问题。 从表面上看,即使您添加逻辑来有条件地处理多个事件,当后续(重复)事件发生时,任何应该处理的代码都将被中断/中止,从而导致不良行为。 我认为解决这个问题的方法是以某种方式在不同的线程上实现事件处理程序......希望这是有道理的。
干杯,
尼科
I found this page for the same problem. And from what it looks like, even if you add logic to conditionally process multiple events, any code that is supposed to be processed will be interrupted/aborted when a subsequent (duplicate) event occurs thereby causing an undesired behavior. I think a way around this would be to implement an event handler on a different thread somehow... hope this makes sense.
Cheers,
Nico
我做了一个简单的课程,对我来说效果很好。 它可能对其他人有用。
可以这样使用:
I made a simple class that works fine for me. It may be useful for someone else.
Can be used like that:
自第一天(自 Windows 3.x 起)以来,这一直是 FindFirstChangeNotification() Win32 API 的一个令人抓狂的怪癖,而且看起来 FileSystemWatcher 只是包装了该 API。 计时器方法(如上所述)是常见的解决方法。
我通常创建一个类来包装 FileSystemWatcher 并执行多次更改调用过滤。 需要编写一些额外的工作,但在重用中会得到回报。
然后,您可以像使用 FileSystemWatcher 一样使用 FileChangeMonitor:
当然,上面的代码仅处理 Changed 事件和 NotifyFilters.LastWrite,但您明白了。
This has been a maddening quirk of the FindFirstChangeNotification() Win32 API since day 1 (since Windows 3.x), and it looks like FileSystemWatcher simply wraps that API. The timer approach (presented above) is the common workaround.
I usually create a class that wraps FileSystemWatcher and does the multiple-change-call filtering. A bit of extra work to write, but it pays off in reuse.
You can then use FileChangeMonitor pretty much like you would FileSystemWatcher:
Of course, the code above only handles the Changed event and NotifyFilters.LastWrite, but you get the idea.
平台无关的技巧:
Platform independent trick :
如果您需要在表单上发生更改事件时显示它们,那么您需要使用线程。 Eric 的解决方案在这方面是最好的,因为无论有没有表单,它都可以轻松使用,从而使解决方案最灵活。 它还可以很好地处理多个重复事件,并确保仅在同一文件时才处理重复事件。 在已接受的解决方案中,如果两个文件几乎同时更改,则其中一个事件可能会被错误地忽略。
If you need to display the change events while they are happening on a form, then you need to use threading. Eric's solution is the best in this regard since it can be easily used with or without a form making the solution most flexible. It also handles the multiple duplicate events nicely and makes sure that it only eats duplicate events only if it is for THE SAME FILE. In the accepted solution, if two files are changed at near the same time, one of their events could be incorrectly ignored.
这是我如何处理这个问题的概念证明。
要进行测试,请创建一个新的 Windows 窗体应用程序。 在窗体上,添加一个名为“tbMonitor”的多行文本框。 右键单击表单并转到“查看代码”。 将该代码替换为我在下面包含的代码。 请注意,我将等待时间设置为一个非常高的数字,以便您可以稍微尝试一下。 在生产中,您可能希望使这个数字低得多,可能在 10 或 15 左右。
Here is a proof of concept for how I handle this.
To test, create a new Windows Forms application. On the form, add a multiline text box named "tbMonitor". Right-click on the form and go to View Code. Replace that code with the code I've included below. Note that I set the wait time to a really high number so you can play around with it a bit. In production, you'll probably want to make this number much lower, probably around 10 or 15.
我通过上面的老挝示例启发了我的解决方案。
我为该文件夹实现了一个观察程序,每次触发它时,我都会停止计时器并再次启动它以重置它。 我仅在计时器结束时触发操作,这可以防止观察者为文件创建触发操作两次。
按照要求,它是在 VB.Net 中:)
I've inspired my solution with LAOS example here above.
I implement a watcher for the folder, and every times it is triggered, I stop a timer and start it again to reset it. I fire my actions only when the timer ends, which prevent watcher from triggering action twice for a file creation.
And as requested, it is in VB.Net :)