FSEvents C++ 示例

Posted

技术标签:

【中文标题】FSEvents C++ 示例【英文标题】:FSEvents C++ Example 【发布时间】:2012-07-19 08:10:37 【问题描述】:

我需要为 Mac 中的文件夹创建 FSEvents 观察程序。我对 C++ 很满意,有没有办法在 C++ 代码而不是 Objective-C 中获取 FSEvents 通知。是否有一些示例代码可以开始以及我需要包含的任何库..?

我已经在这个页面上了。 http://developer.apple.com/library/mac/#featuredarticles/FileSystemEvents/_index.html

但是好像只有Objective C,我可以有它的CPP版本吗

【问题讨论】:

【参考方案1】:

是的,在 C 中是可能的。你应该寻找内核队列。

这里有一个小示例来观看目录:

#include <errno.h>       // for errno
#include <fcntl.h>       // for O_RDONLY
#include <stdio.h>       // for fprintf()
#include <stdlib.h>      // for EXIT_SUCCESS
#include <string.h>      // for strerror()
#include <sys/event.h>   // for kqueue() etc.
#include <unistd.h>      // for close()

int main (int argc, const char *argv[])

   int kq = kqueue ();
   // dir name is in argv[1], NO checks for errors here
   int dirfd = open (argv[1], O_RDONLY);

   struct kevent direvent;
    EV_SET (&direvent, dirfd, EVFILT_VNODE, EV_ADD | EV_CLEAR | EV_ENABLE,
            NOTE_WRITE, 0, (void *)dirname);

   kevent(kq, &direvent, 1, NULL, 0, NULL);

   // Register interest in SIGINT with the queue.  The user data
   // is NULL, which is how we'll differentiate between
   // a directory-modification event and a SIGINT-received event.
   struct kevent sigevent;
   EV_SET (&sigevent, SIGINT, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, NULL);
   // kqueue event handling happens after the legacy API, so make
   // sure it doesn eat the signal before the kqueue can see it.
   signal (SIGINT, SIG_IGN);

   // Register the signal event.
   kevent(kq, &sigevent, 1, NULL, 0, NULL);

   while (1) 
       // camp on kevent() until something interesting happens
       struct kevent change;
       if (kevent(kq, NULL, 0, &change, 1, NULL) == -1)  exit(1); 
       // The signal event has NULL in the user data.  Check for that first.
       if (change.udata == NULL) 
           break;
        else 
        // udata is non-null, so it's the name of the directory
        printf ("%s\n", (char*)change.udata);
       
   
   close (kq);
   return 0;

详细信息可以在 ch 中找到。 Mark Dalrymple 的“高级 Mac OSX 编程”的 16(kqueues 和 FSEvents)。附加信息可以在 kqueue 的 *BSD 文档中找到。

或者使用 FSEvents 的这个 API(它主要是基于 C 的)。

FSEventStreamRef FSEventStreamCreate (CFAllocatorRef allocator,
                                  FSEventStreamCallback callback,
                                  FSEventStreamContext *context,
                                  CFArrayRef pathsToWatch,
                                  FSEventStreamEventId sinceWhen,
                                  CFTimeInterval latency,
                                  FSEventStreamCreateFlags flags);

使用纯 C 回调创建 FSEvents 事件流。

然后使用

将此事件流附加到您的运行循环
void FSEventStreamScheduleWithRunLoop (FSEventStreamRef streamRef,
                                   CFRunLoopRef runLoop,
                                   CFStringRef runLoopMode);

是的,这里你可能应该使用一行 Obj-C 来获取 RunLoop 句柄:使用 -getCFRunLoop 从 NSRunLoop 获取 CFRunLoop

CFRunLoop* loopRef = [[NSRunLoop currentRunLoop] getCFRunLoop];

或使用纯 C 调用

CFRunLoop* loopRef =  CFRunLoopGetCurrent();

启动事件流

Boolean FSEventStreamStart (FSEventStreamRef streamRef);

停止事件流

void FSEventStreamStop (FSEventStreamRef streamRef);

然后使用以下命令从运行循环中取消调度它:

void FSEventStreamUnscheduleFromRunLoop (FSEventStreamRef streamRef,
                                     CFRunLoopRef runLoop,
                                     CFStringRef runLoopMode);

使流无效(清理):

void FSEventStreamInvalidate (FSEventStreamRef streamRef);

希望这能让你开始。

【讨论】:

在我的实验中,kqueue 在功能上并不等同于 FSEvents。感谢您概述 CFRunLoop 位! 在您的第一个小样本中,似乎没有定义“目录名”...? @Sugar:你说得对,const char* dirname = "some_dir_name" 肯定不见了。其实也可以是const char* dirname = argv[1]; @ViktorLatypov 谢谢,你的样本真的很有帮助! :)

以上是关于FSEvents C++ 示例的主要内容,如果未能解决你的问题,请参考以下文章

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

带有springboot应用程序的角度上的fsevents错误

C++ 中的 Lambda 泛型

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

如何将 kFSEventStreamEventFlagEventIdsWrapped 与 FSEvents 一起使用?

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