我需要设置一个应用程序来监视在本地或网络驱动器上的目录中创建的文件。
计时器上的FileSystemWatcher
或轮询是否是最佳选择。我过去曾使用过这两种方法,但并不广泛。
两种方法都有哪些问题(性能,可靠性等)?
答案 0 :(得分:105)
我在生产和测试环境中看到文件系统观察程序失败。我现在认为它很方便,但我认为它不可靠。我的模式是使用文件系统观察程序来监视更改,但偶尔进行轮询以捕获丢失的文件更改。
编辑:如果您有用户界面,您还可以让用户“刷新”更改而不是轮询。我会将它与文件系统观察器结合起来。
答案 1 :(得分:60)
我遇到的最大问题是当缓冲区满了时丢失文件。很容易修复 - 只需增加缓冲区。请记住,它包含文件名和事件,因此请将其增加到预期的文件数量(试用和错误)。它确实使用了无法分页的内存,因此如果内存不足,它可能会强制其他进程进行分页。
以下是有关缓冲区的MSDN文章: FileSystemWatcher..::.InternalBufferSize Property
每个MSDN:
增加缓冲区大小是昂贵的,因为它来自无法换出到磁盘的非分页内存,因此请尽可能减小缓冲区。要避免缓冲区溢出,请使用NotifyFilter和IncludeSubdirectories属性过滤掉不需要的更改通知。
我们使用16MB,因为一次预计会有大量批次。工作正常,永远不会遗漏文件。
我们还在开始处理之前读取所有文件,即使只有一个文件......将文件名安全地缓存(在我们的例子中,放入数据库表中)然后处理它们。
对于文件锁定问题,我产生了一个进程,它等待文件解锁等待一秒钟,然后是两秒钟,然后是四个等等。我们从不民意调查。这已经生产了大约两年没有错误。
答案 2 :(得分:34)
如果排队的更改数量溢出提供的缓冲区,则FileSystemWatcher
也可能在繁忙时间内错过更改。这不是.NET类本身的限制,而是基础Win32基础结构的限制。根据我们的经验,最小化此问题的最佳方法是尽快将通知出列并在另一个线程上处理它们。
如上面的@ChillTemp所述,观察者可能无法处理非Windows共享。例如,它在安装的Novell驱动器上根本不起作用。
我同意一个很好的妥协方案是偶尔进行一次民意调查以获取任何遗漏的变化。
答案 3 :(得分:17)
另请注意,文件系统观察程序在文件共享上不可靠。特别是如果文件共享托管在非Windows服务器上。 FSW不应用于任何关键的事情。或者应该与偶尔的民意调查一起使用,以验证它没有错过任何内容。
答案 4 :(得分:11)
就个人而言,我在生产系统上使用了FileSystemWatcher
,并且运行良好。在过去的6个月中,它没有一次性打嗝全天候运行。它正在监视单个本地文件夹(共享)。我们必须处理相对较少的文件操作(每天触发10个事件)。这不是我曾经不必担心的事情。如果我不得不重新制定决定,我会再次使用它。
答案 5 :(得分:7)
我目前在平均每100毫秒更新的XML文件上使用FileSystemWatcher
。
我发现只要FileSystemWatcher
配置正确,就不会出现本地文件的问题。
我没有远程文件监视和非Windows共享的经验。
我会考虑将文件轮询为冗余并且不值得花费开销,除非您本身不信任FileSystemWatcher
或直接遇到其他人在此列出的限制(非Windows共享和远程文件监视)。
答案 6 :(得分:5)
我在网络共享上使用FileSystemWatcher
遇到了麻烦。如果你在纯Windows环境中,它可能不是问题,但我正在观看NFS共享,因为NFS是无状态的,所以当我正在观看的文件发生变化时,从来没有通知。
答案 7 :(得分:5)
我会参加投票。
网络问题导致FileSystemWatcher
不可靠(即使在重载错误事件时也是如此)。
答案 8 :(得分:3)
我在网络驱动器上遇到了FSW的一些大问题:删除文件总是引发错误事件,而不是删除事件。我没有找到解决方案,所以我现在避开FSW并使用轮询。
另一方面,创建事件工作得很好,所以如果你只需要注意创建文件,就可以去FSW。
此外,无论是否共享,我在本地文件夹上都没有任何问题。
答案 9 :(得分:2)
在我看来,使用FSW 和轮询是浪费时间和资源,我很惊讶有经验的开发人员提出建议。如果您需要使用轮询来检查任何" FSW未命中",那么您自然可以完全丢弃FSW并仅使用轮询。
我目前正在尝试决定是否将FSW 或轮询用于我开发的项目。阅读答案很明显,有些情况下FSW完全满足需求,而有时候,你需要轮询。不幸的是,没有答案实际上已经处理了性能的差异(如果有的话),只有"可靠性"的问题。是否有人可以回答问题的这一部分?
编辑:nmclean 指出使用FSW和轮询的有效性(如果您感兴趣,可以阅读评论中的讨论)似乎是一个非常合理的解释为什么会出现同时使用FSW和轮询 有效的情况。感谢您为我(以及其他任何有相同观点的人)阐明了这一点, nmclean 。
答案 10 :(得分:2)
使用另一个线程尽快从事件方法返回,为我解决了这个问题:
private void Watcher_Created(object sender, FileSystemEventArgs e)
{
Task.Run(() => MySubmit(e.FullPath));
}
答案 11 :(得分:1)
使用create event而不是更改的工作解决方案
即使是复制,剪切,粘贴,移动。
Enumeration
使用静态存储的文件属性更改事件时此文件观察程序的解决方案
class Program
{
static void Main(string[] args)
{
string SourceFolderPath = "D:\\SourcePath";
string DestinationFolderPath = "D:\\DestinationPath";
FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
FileSystemWatcher.Path = SourceFolderPath;
FileSystemWatcher.IncludeSubdirectories = false;
FileSystemWatcher.NotifyFilter = NotifyFilters.FileName; // ON FILE NAME FILTER
FileSystemWatcher.Filter = "*.txt";
FileSystemWatcher.Created +=FileSystemWatcher_Created; // TRIGGERED ONLY FOR FILE GOT CREATED BY COPY, CUT PASTE, MOVE
FileSystemWatcher.EnableRaisingEvents = true;
Console.Read();
}
static void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
string SourceFolderPath = "D:\\SourcePath";
string DestinationFolderPath = "D:\\DestinationPath";
try
{
// DO SOMETING LIKE MOVE, COPY, ETC
File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
}
catch
{
}
}
}
这是针对此多重触发事件问题的解决方案。
答案 12 :(得分:0)
我会说使用轮询,尤其是在TDD场景中,因为模拟/存根文件或者在触发轮询事件时比依赖更“不受控制”的fsw事件更容易。 +已经处理了许多受fsw错误困扰的应用程序。