使用 Lion 上的 FSEvents 跟踪文件重命名/删除
我正在尝试使用 FSEvents 来检测何时从特定文件夹添加/删除文件。目前,我围绕 FSEvents 实现了一个简单的包装器,它工作得很好:我得到了所有事件。
但我现在遇到的问题是,当我在 Finder 中重命名文件时,我捕获了 2 个不同的事件:第一个事件的类型为“重命名”,使用旧文件名,另一个事件的类型为“重命名”和新文件名。两次调用之间的事件 ID 不同。
那么,我应该如何知道哪个“重命名”事件包含旧名称,以及哪个事件包含旧名称?我尝试查看文档,但不幸的是,kFSEventStreamEventFlagItemRenamed 没有记录...它在 Lion 中似乎是新的。
PS:我能想到的唯一方法是:在重命名的事件中,我检查用户界面以查看是否有与事件路径相对应的项目。如果是这样,我会将其标记为重命名。如果没有,我检查某个项目是否被标记为重命名,如果是,则将其重命名为新的事件路径。但我真的不喜欢这个想法......
编辑:好的,我沿着我的“PS”的思路实现了一些东西:我注意到重命名某些东西时,两个事件的 id 是连续的,因此 id包含新名称的事件,我可以获得包含旧名称的事件。我只是在界面中使用一个小字典来存储“重命名”事件时的 ID 和关联路径。
无论如何,我现在可以捕获重命名事件,甚至移动事件:当您移动文件时,这是一个由 FSEventStream 捕获的“重命名”事件...
但是,我仍然有最后一个问题:删除。当我删除某些内容时,它会移至回收站:我收到“重命名”事件。但问题是我没有收到第二个重命名事件。仅 .DS_Store 文件上的“修改”事件。我认为 Finder 使用此文件来了解 bin 中有哪些文件等。因此我可以检查对此文件的修改,并获取最后一个“重命名”事件来检测文件是否已发送到 bin。但我使用的是 TotalFinder,它使用 Asepsis,它修改了 Finder 存储 .DS_Store 文件的方式:我不再收到对此的“修改”。 总结一下:我无法检测文件何时发送到垃圾箱......
知道我该怎么做吗?也许使用 FSEvents 之外的其他东西来仅捕获此事件?
I'm trying to use FSEvents to detect when files were added/removed from a specific folder. For the moment, I implemented a simple wrapper around FSEvents, and it works fine : I get all the events.
BUT the problem I have now is that when I rename a file in the Finder, I catch 2 distinct events : the first one of type "renamed" with the old file name, and another one with "renamed" and the new filename. The event ids are different between both calls.
So, how am I supposed to know which "renamed" event contains the old name, and which event contains the old one ?? I tried looking in the documentation, but unfortunately, kFSEventStreamEventFlagItemRenamed is not documented ... it seems new in Lion.
PS: the only way I could think of was : on a renamed event, I check my UI to see if I have an item corresponding to the event path. If so, I flag it for renaming. If not, I check if an item was flagged for renaming, and if so, then I rename it to the new event path. But I really don't like this idea ...
Edit: Ok, I imlemented something along the line of my "PS" : I noticed that when renaming something, the ids of the 2 events are consecutives, so that with the id of the event containing the new name, I can get the event containing the old name. I simply use a little dictionnary in my interface to store ids and associated paths in the case of a "renamed" event.
Anyway, I can now catch rename events, and even move events : when you move a file, it's a "renamed" event which is caught by the FSEventStream ...
But, I still have one last problem : deleting. When I delete something, it's moved to the recycle bin : I receive a "renamed" event. But the problem is that I don't receive the second rename event. Only a "modified" event on the .DS_Store file. I think this file is used by the Finder to know which files are in the bin, etc. So I could check modification to this file, and get the last "renamed" event to detect that a file was sent to the bin. But I'm using TotalFinder which uses Asepsis, which modifies the way the Finder stores .DS_Store files : I no longer receive "modified" on this.
To sumarize : I can't detect when a file is sent to the bin ...
Any idea how I can do that ? Maybe use something else than FSEvents to catch only this event ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好吧,我没有找到问题的完美答案,但我找到了一个最终令我非常满意的解决方案,所以我想我可以分享^^
正如我所说,当将东西移至垃圾箱时,如果您仅观看 1 个文件夹,您将无法捕捉到图像被放入垃圾箱时生成的事件。因此,我决定执行以下操作:
我有一个类,它在根文件夹(“/”)上创建一个流,以便它捕获所有事件 ->这解决了文件被发送到垃圾箱以及所有此类问题的问题。然后,此类允许在某些路径上注册委托。因此,我没有创建许多流,而是创建一个大流,然后根据需要过滤事件,并创建许多委托。
因此,当我想要观看特殊文件夹上的事件时,我现在要做的就是:
我只需在应用程序启动时创建 FSEventListener 的实例,并在应用程序停止时释放它。
我只需要实现以下 3 个将被自动调用的方法:
如果您对这个小实用程序的源代码感兴趣,您可以在这里查看:http://blog.pcitron.fr/tools/macosx-imageviewer/ (该实用程序是在 0.8 版本中添加的)
我将其开发为一个小图像查看器的一部分,以保持UI同步与磁盘内容(它显示每个目录中包含的图像数量等)源代码可用,实用程序位于 Utils/FSEventsListener.h/.m 中。
如果万一有人真正下载了该应用程序并查看了源代码,如果您发现任何有用的内容(性能/功能改进等),请随时发表评论/邮件^^
Well, I didn't find the perfect answer to my question, but I found a solution which I eventually was really satisfied with, so I thought I might share ^^
As I said, when moving stuff to the trash, if you're only watching 1 folder, you won't catch the event generated when the image is put in the trash. So, I decided to do the following :
I have a class which creates a stream on the root folder ("/") so that it will catch all the events -> this solves the problem of files being sent to the trash, and all such stuff. Then, this class allow to register delegates on certain pathes. So, instead of creating many streams, I create one big stream, then filter events as needed, and I create many delegates.
So all I have to do now when I want to watch events on a special folder is the following :
I just have to create an instance of FSEventListener at application start, and release it when the app stops.
And I just need to implement the following 3 methods which will be automatically called :
If you're interested in the source code of this little utility, you can check here : http://blog.pcitron.fr/tools/macosx-imageviewer/ (the utility was added at the version 0.8)
I developed it as part of a a little image viewer to keep the UI synchronized with the disk content (it displays the number of images contained in each directories, etc.) The source code is available, and the utility is in Utils/FSEventsListener.h/.m.
And if by any chance someone actually downloads the application and take a look at the sources, if you find anything usefull (performance / feature improvement, whatever) feel free to drop a comment / mail ^^
您实际上提出了两个与 FSEvents 和重命名相关的问题。
1. 文件被重命名,新旧文件名都在受监视的目录树中。
2. 文件被重命名,并且其中一个名称不在正在监视的目录树中。
您已经(几乎)解决了第一个问题。还需要为您的应用程序提供一种方法来了解同一 FSEvent 事件组中正在报告哪些事件。仅当两个重命名属于同一延迟期内报告的同一组事件时,您了解连续报告两个重命名的方法才有效。如果两个类型 2 的重命名事件相继发生,但不在同一延迟组中报告的同一组事件中,则它们实际上彼此无关 - 并且您会错误地认为一个文件已重命名为另一个文件。
可以通过使用根目录简单地监视系统中的每个目录来处理第二种类型的重命名,但这会给您带来许多不必要的事件。您可以通过对文件执行 stat() 来确定“部分”重命名是否是文件从受监视的目录树移出或移入受监视的目录树的结果。如果 stat() 失败且 errno 为 2,则该文件已移至正在监视的目录之外,并且可以将其视为已被删除。如果 stat() 成功,则可以将该事件视为文件已创建。
You are actually raising two issues related to FSEvents and renames.
1. A file is renamed and both the old and new file names are within the directory trees being monitored.
2. A file is renamed and one of the names is not in the directory trees being monitored.
You have solved (almost) the first issue. It is also necessary to provide your application with a means of knowing which events are being reported in the same FSEvent group of events. Your method of knowing that two renames are reported consecutively only works if they are within the same group of events being reported within the same latency period. If two rename events of type 2 occur one after another but are not within the same group of events being reported in the same latency group, they actually have nothing to do with each other - and you will mistakenly think one file has be renamed to another.
It is possible to handle the second type of rename by simply monitoring every directory in the system using the root, but this will flood you with many unnecessary events. You can determine if a "partial" rename is the result of a file being moved out of the directory tree being monitored or into the directory tree being monitored by doing a stat() on the file. If stat() fails with an errno of 2, then the file has been moved outside the directory being monitored, and it can be treated as if it has been deleted. If stat() succeeds, the event can be treated as if the file has been created.