【问题标题】:Why do FindFirstFile / FindNextFile sometimes see a file on a network folder, but CopyFile does not?为什么 FindFirstFile / FindNextFile 有时会看到网络文件夹中的文件,而 CopyFile 却看不到?
【发布时间】:2015-04-22 12:45:36
【问题描述】:

我有一个功能应该通过将所有文件从源文件夹复制到目标文件夹来创建源文件夹的备份。该函数使用由FindFirstFile / FindNextFile 驱动的while 循环,然后为Find... 函数找到的每个文件调用CopyFile

现在当源文件夹是 SMB 网络路径(无论我使用映射驱动器还是 UNC 路径)时,有时会发生 FindNextFile“看到”文件,但 CopyFile 拒绝复制文件.错误码为2,即ERROR_FILE_NOT_FOUND

我觉得这难以置信,所以我在备份函数中添加了对_access 的调用,该函数在调用CopyFile 之前检查文件是否存在。结果与CopyFile相同,即_access报告文件不存在(返回码-1和errno为2,即ENOENT)。

所以我的主要问题是:FindFirstFile / FindNextFile 怎么可能“看到”CopyFile_access 都看不到的网络文件夹上的文件?

其他信息/诊断:

  • 有问题的文件是在运行备份功能之前创建的文件。具体来说,它是这样工作的:在客户端机器上运行的进程与在服务器机器上运行的进程有网络连接。客户端进程告诉服务器进程创建文件。这应该是同步工作的:只有在服务器进程确认它已创建文件后,客户端进程才会继续执行备份。
  • 我在备份功能中添加了重试机制。有了这个,CopyFile_access 在重试大约 4 秒后突然开始看到有问题的文件。这向我表明确实存在某种网络延迟。似乎FindFirstFile / FindNextFile 访问网络路径的方式与CopyFile / _access 不同。

不幸的是,我对此效果的研究没有发现任何有用的信息,所以我只能推测。如果FindFirstFile / FindNextFile / CopyFile 确实不能很好地协同工作,您是否知道另一组更可靠的查找/复制 API 函数?

【问题讨论】:

  • @HansPassant 好主意,但在这种情况下,罪魁祸首确实是 SMB 缓存(请参阅接受的答案)。

标签: c++ windows winapi smb


【解决方案1】:

这可能是由于 Windows 上的 SMB 2.0 维护了一个缓存,该缓存仅每 10 秒刷新一次。

请参阅this blog archive 文章了解更多信息和编程解决方法。

File.Exists /_access / GetFileAttributes / FindFirstFile,FindNextFile / _stat 在 SMB 2.0 上的行为

到底发生了什么?

这是因为客户端包含本地缓存 中小企业 2.0。创建 SMB 2.0 会话后,本地缓存 将在客户端可用,之后会刷新 默认情况下每 10 秒一次。存在对该文件的任何进一步请求 将针对此本地缓存进行检查,而不是转到 服务器共享。因此,如果在客户端和服务器上构建本地缓存 共享一个新文件已创建,本地缓存尚未失效并且 与服务器共享不同步,任何进一步的检查请求 新文件存在将失败。

这是根本原因,但这是设计使然。如果本地缓存更新并与服务器共享同步,请求就会成功。

对于解决方案/解决方法,链接文章提到:

如何控制本地缓存生存期?

您可以在下面创建注册表项来控制缓存的生命周期。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters下:

  • FileInfoCacheLifetime
  • FileNotFoundCacheLifetime
  • DirectoryCacheLifetime

它们都是以秒为单位的 REG_DWORD 类型。

程序化解决方法?

使用 Win32 API 注册目录或文件更改通知。
使用FindFirstChangeNotification Function (Windows) API 注册更改。

【讨论】:

  • 很有趣,但你如何解释FindNextFile 确实看到了文件?
  • 我假设会有一些 API 使用缓存,有些则没有,但文章确实没有明确说明哪些 API 使用(以及 CopyFile 是否使用了任何提到的那些)。我的建议是尝试上述解决方案,以了解是否是导致此问题的缓存,并查看是否提供了有效的解决方法 - 如果它是缓存,则上述注册表项应该有助于您的 search-fu 找到其他文章/questions 涵盖此问题。
  • 我尝试通过文章中的注册表项禁用缓存,之后CopyFile 按预期工作。因此,在我的情况下,SMB 缓存确实是罪魁祸首。我仍然需要决定是实现一个愚蠢但简单的重试机制,还是采用更复杂但也更复杂的FindFirstChangeNotification 方法。无论如何,非常感谢您的帮助!
  • 这听起来像是他们缓存算法中的一个错误。我可以理解是否另一台 PC 创建了该文件 - 因为那么谁说他们在我尝试读取文件之前创建了该文件?总会有时间的不确定性。但是如果 创建了文件,那么 SMB 重定向器应该会看到它并相应地更新其缓存。
猜你喜欢
  • 1970-01-01
  • 2023-03-16
  • 2012-05-13
  • 1970-01-01
  • 2016-02-29
  • 2013-07-22
  • 1970-01-01
  • 2016-01-10
  • 1970-01-01
相关资源
最近更新 更多