Cocoa、FSEvents、kFSEventStreamCreateFlagFileEvents 标志和“重命名”事件

Posted

技术标签:

【中文标题】Cocoa、FSEvents、kFSEventStreamCreateFlagFileEvents 标志和“重命名”事件【英文标题】:Cocoa, FSEvents, kFSEventStreamCreateFlagFileEvents flag and "renamed" events 【发布时间】:2011-11-29 16:40:25 【问题描述】:

我一直在我的一个小应用程序中使用FSEvents 来将我的应用程序的内容与硬盘驱动器上的内容同步(基本上,它是一个小图像查看器,我希望它的内容在内容时更新硬盘变化)

我使用kFSEventStreamCreateFlagFileEvents 标志创建我的流,但我很难弄清楚这些事件是如何由操作系统(或内核,或其他)生成的,不幸的是,没有关于使用生成的事件的文档这个标志......似乎它们是 10.7 的新功能,并且仍然没有记录。

所以,我的主要问题是“重命名”。当我进行简单的重命名时,会向我的回调发送 2 个 kFSEventStreamEventFlagItemRenamed 事件。一个包含旧文件名,第二个包含新文件名。当您重命名一批文件时会出现问题,这些事件可能不是连续的。比如下面这种情况:

    “file1”->“new_file_1” “file2”->“new_file_2”

我可能会按此顺序接收事件:

    “重命名”/“file1” “重命名”/“file2” “重命名”/“new_file_1” “重命名”/“new_file_2”

当你捕捉到第二个重命名事件时,似乎没有任何方法可以获取第一个重命名事件的 id ...所以我所做的是:当接收到“重命名”事件时,我会执行 stat( ) 与文件名。如果stat返回成功,则表示它是新的文件名。如果不是,则说明它是旧的。我仍然无法链接这两个事件,但至少我可以通过删除旧文件并添加新文件来解决问题。

所以,我基本上有两个问题:

首先是:我是不是完全失明了,没有看到通过 fsevents 正确捕获“重命名”事件的明显方法?

第二个 i:我有时会遇到一个奇怪的错误,不是只发送 2 个重命名的事件,而是发送了 3 个!所以我得到一个文件添加了两次......我不确定这是否是一个错误,或者这是否来自我完全错过了使用带有 kFSEventStreamCreateFlagFileEvents 标志的 fsevent API 的事实......

欢迎任何帮助,我完全没有解决这个问题的想法!

【问题讨论】:

【参考方案1】:

您需要使用标志 kFSEventStreamCreateFlagUseExtendedData(自 OS X 10.13 起可用)。使用该标志创建的流将包含事件文件的 inode。这样您就可以检测报告的事件批次中发生的“重命名链”。

附: macOS 可能会为新创建的文件重用已删除文件的 inode,但如果您立即处理事件,风险可以忽略不计。

【讨论】:

【参考方案2】:

由于这些事件只处理路径,因此您必须做一些额外的工作来处理重命名。一种选择是跟踪您感兴趣的文件的 inode 编号。因此,当您执行该 stat 调用时,还要记下 inode 编号并查看它是否与您正在跟踪的任何文件匹配。

但请注意,操作系统可能会重复使用已删除文件的 inode 编号,因此将它们作为唯一标识符并非万无一失。

【讨论】:

【参考方案3】:

您可以通过从路径中创建一个 URL 来获取文件 ID,然后调用:

NSString *fileID = nil;

[url getResourceValue:&fileID forKey:NSURLFileResourceIdentifierKey error:&error]; //NS_AVAILABLE(10_7, 5_0);

(此标识符在系统重新启动后不会持久)

【讨论】:

以上是关于Cocoa、FSEvents、kFSEventStreamCreateFlagFileEvents 标志和“重命名”事件的主要内容,如果未能解决你的问题,请参考以下文章

未通过 FSEvents 检测到 sftp 文件修改

如何将 kFSEventStreamEventFlagEventIdsWrapped 与 FSEvents 一起使用?

Laravel/Vue/Heroku - 不支持作为平台 linux 跳过“fsevents”构建

如何在 mac osx 10.6 中使用 fsevents 创建观察者

FSEvents - 获取执行操作的进程的 PID

失败的可选依赖项/ chokidar / fsevents: