如何轮询大量文件以检测更改?

8
我想轮询文件系统以查找任何更改、添加或删除的文件或子目录。所有更改应该快速检测到,但不会对计算机造成压力。操作系统为Windows >= Vista,观察的部分是本地目录。
通常,我会使用FileSystemWatcher,但这会导致其他试图监视同一位置的程序出现问题(尤其是Windows资源管理器)。而且我听说FSW即使对于本地文件夹和大缓冲区也不是真正可靠的。
我主要的问题是文件和目录的数量可能非常大(约7位数)。每秒运行所有文件的检查显然会影响我的机器。
我的下一个想法是每秒钟检查整个树的不同部分,以减少总体影响,并可能添加一种启发式方法,例如快速连续检查经常更改的文件。
我想知道是否有这种问题的模式,或者是否有人有这种情况的经验。

所有子文件夹都在同一个根目录下吗?您在Windows资源管理器中遇到了什么问题?这是一种模式,可以确保您不会错过任何消息。https://dev59.com/VlTTa4cB1Zd3GeqPqjsG#4968391 - adrianm
@adrianm:是的,同一个根目录。--- 当监视的文件夹发生更改时,资源管理器没有更新其视图,我想这是因为FSW窃取了它的事件。 - mafu
3个回答

3
我们使用C#实现了类似的功能。当目录树很大时,FileSystemWatcher效率低下。我们采用了FSNodes作为替代方案,这是我们创建的一个结构体,使用了以下Windows API调用:
    [StructLayout(LayoutKind.Sequential)]
        private struct FILETIME
    {
        public uint dwLowDateTime;
        public uint dwHighDateTime;
    };

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
        private struct WIN32_FIND_DATA
    {
        public FileAttributes dwFileAttributes;
        public FILETIME ftCreationTime;
        public FILETIME ftLastAccessTime;
        public FILETIME ftLastWriteTime;
        public uint nFileSizeHigh;
        public uint nFileSizeLow;
        public int dwReserved0;
        public int dwReserved1;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_PATH)]
        public string cFileName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_ALTERNATE)]
        public string cAlternate;
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool FindClose(IntPtr hFindFile);

    [DllImport("kernel32", CharSet=CharSet.Unicode)]
    private static extern IntPtr FindFirstFile(
        string lpFileName, out WIN32_FIND_DATA lpFindFileData);

    [DllImport("kernel32", CharSet=CharSet.Unicode)]
    private static extern bool FindNextFile(
        IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

我们所做的是静态处理。我们在磁盘上保存元数据树,并比较存储的目录树与加载的目录树,搜索已修改的文件(根据其时间戳(更快),或者根据文件哈希值),同时我们可以管理删除、添加和移动,甚至是移动-修改的文件(也基于文件哈希)。
这种实现与执行每个POLL_TIME的守护程序混合在一起,对我们很有效。希望这可以帮到你。

你能稍微解释一下你是如何使用Win32 API调用的吗? - Cocowalla
FindFirstFile 函数在目录中搜索与特定名称(或使用通配符的部分名称)匹配的文件或子目录。FindNextFile 函数从上一次调用 FindFirstFileFindFirstFileEx 函数开始继续文件搜索。FindClose 函数关闭由 FindFirstFile(和其他)函数打开的文件搜索句柄。我建议进行谷歌搜索以更好地了解该 API。 - Daniel Peñalba

1

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接