我目前正在为OpenFOAM输出文件实现文件内容监视器。这些文件由OpenFOAM在Unix环境中编写,并由我的应用程序在Windows环境中使用。
请考虑我的第一个工作观察程序用于收敛文件(这些文件在解决方案的每次迭代后都会更新):
FileSystemWatcher watcher;
watcher = new FileSystemWatcher(WatchPath, "convergenceUp*.out");
watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Attributes | NotifyFilters.FileName | NotifyFilters.Size;
watcher.Changed += Watcher_Changed;
watcher.EnableRaisingEvents = true;
private void Watcher_Changed(object sender, FileSystemEventArgs e)
{
Files = Directory.GetFiles(WatchPath, "convergenceUp*.out").OrderBy(x => x).ToList(); // Update List of all files in the directory
ReadFiles(); // Do fancy stuff with the files
}
这可以按预期工作。每次在监视目录中更改与模式匹配的文件(Notepad ++确实通知我文件已更改),文件将被处理。
从这个简单的“所有文件都在一个目录中”场景开始,我开始为不同类型的文件构建一个观察者(对于那些熟悉OpenFOAM的人来说,强制函数对象)。这些文件保存在分层文件夹结构中,如下所示:
NameOfFunctionObject
|_StartTimeOfSolutionSetup#1
| |_forces.dat
|_StartTimeOfSolutionSetup#2
|_forces.dat
我的目标是从“NameOfFunctionObject”读取所有的force.dat,并对所有包含的数据做一些诡计。此外,我还希望有机会阅读和观看一个文件。所以我的实现(从上面大量借鉴)目前看起来像这样:
FileSystemWatcher watcher;
if (isSingleFile)
watcher = new FileSystemWatcher(Directory.GetParent(WatchPath).ToString(), Path.GetFileName(WatchPath));
else
watcher = new FileSystemWatcher(WatchPath, "forces.dat");
watcher.IncludeSubdirectories = !isSingleFile;
watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Attributes | NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.DirectoryName | NotifyFilters.LastAccess | NotifyFilters.CreationTime | NotifyFilters.Security;
watcher.Changed += Watcher_Changed;
watcher.Created += Watcher_Created;
watcher.Deleted += Watcher_Deleted;
watcher.Error += Watcher_Error;
watcher.Renamed += Watcher_Renamed;
watcher.EnableRaisingEvents = isWatchEnabled;
因此,我只想看一个文件或多个文件,我设置了要监视的目录和文件过滤器。如果我观看多个文件,我会将观察者设置为观看子目录。由于进行了严格的测试,我会过滤所有通知并捕获所有观察者事件。
如果我测试单个文件选项,一切都按预期工作,报告并正确处理对文件的更改(同样,使用可信赖的旧Notepad ++进行检查) 在测试多文件选项时,事情变得梨形。 文件路径正确,初始读取按预期工作。但观察者事件都没有发生。好奇的一点是:Notepad ++仍在哔哔声,说文件已经改变,Windows资源管理器显示一个新的文件日期和一个新的文件大小。如果我在Notepad ++中保存文件,则会触发观察者。如果我创建一个匹配模式的新文件,则在监视目录(顶层或以下无关紧要!)后,观察者将被触发。即使正在查看。的过滤器来捕获临时文件的创建也不会触发,因此可以安全地假设没有创建临时文件。
通常,观察者的行为符合预期,它可以检测单个文件的更改,它可以检测根目录文件夹及其子文件夹中文件的创建。一旦文件位于子文件夹中,它就无法识别文件的非窗口更改。这种行为是设计的吗?更重要的是:如何在不使用定时器和手动轮询的情况下优雅地工作?
答案 0 :(得分:2)
我认为这可能与你有关
FileSystemWatcher
使用ReadDirectoryChangesW
Winapi 调用一些相关的标记
当您第一次呼叫
ReadDirectoryChangesW
时,系统会分配一个 缓冲区来存储更改信息。此缓冲区与 目录句柄,直到它关闭,其大小不会改变 在其一生中。调用之间发生的目录更改 此函数被添加到缓冲区,然后返回下一个 呼叫。 如果缓冲区溢出,则缓冲区的全部内容都是 丢弃强>
FileSystemWatcher
中的模拟是FileSystemWatcher.InternalBufferSize
属性
备注您可以将缓冲区设置为4 KB或更大,但不能 超过64 KB。如果您尝试将InternalBufferSize属性设置为 小于4096字节,你的值被丢弃了 InternalBufferSize属性设置为4096字节。为了最好 性能,在基于Intel的计算机上使用4 KB的倍数。
系统通知组件文件更改,并存储这些更改 组件创建的缓冲区中的更改并传递给API。的每个 事件最多可以使用16个字节的内存,不包括文件名。 如果短时间内有很多变化,缓冲区可能会溢出。 这会导致组件无法跟踪目录中的更改, 它只会提供全面通知。增加的大小 缓冲区可以防止丢失文件系统更改事件。然而, 增加缓冲区大小是昂贵的,因为它来自非分页 无法换出到磁盘的内存,因此请将缓冲区保持为小 尽可能。 要避免缓冲区溢出,请使用NotifyFilter和 IncludeSubdirectories属性可过滤掉不需要的更改 通知强>
如果情况变得更糟,你可以使用混合的轮询和跟踪,它帮助我摆脱了几次麻烦