Пример FSEvents C++

Мне нужно создать наблюдатель FSEvents для папки на Mac. Мне удобно с C++, и есть ли способ получать уведомления FSEvents в коде C++, а не в Objective-C. Есть ли какой-нибудь пример кода для начала и какие-либо библиотеки, которые мне нужно включить?

Я уже на этой странице. http://developer.apple.com/library/mac/#featuredarticles/FileSystemEvents/_index.html

Но, похоже, есть только Objective C, могу ли я получить его CPP-версию?


person Zeus    schedule 19.07.2012    source источник


Ответы (1)


Да, это возможно в C. Вам следует искать Kernel Queues.

Вот небольшой пример для просмотра каталога:

#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;
}

Подробности можно найти в гл. 16 (kqueues и FSEvents) книги «Advanced Mac OSX Programming» Марка Далримпла. Дополнительную информацию можно найти в документации *BSD для kqueues.

Или используйте этот API от FSEvents (в основном он основан на C).

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

для создания потока событий FSEvents с обратным вызовом на чистом C.

Затем прикрепите этот поток событий к циклу выполнения с помощью

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

Да, здесь вам, вероятно, следует использовать строку Obj-C, чтобы получить дескриптор RunLoop: получить CFRunLoop из NSRunLoop с помощью -getCFRunLoop

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);

Надеюсь, это поможет вам начать.

person Viktor Latypov    schedule 19.07.2012
comment
В моих экспериментах kqueue функционально не эквивалентен FSEvents. Спасибо за описание бита CFRunLoop! - person berkus; 07.01.2014
comment
В вашем первом небольшом образце кажется, что имя каталога не определено...? - person Sugar; 01.06.2021
comment
@Sugar: Вы правы, const char* dirname = "some_dir_name" определенно отсутствует. На самом деле это может быть просто const char* dirname = argv[1]; - person Viktor Latypov; 01.06.2021
comment
@ViktorLatypov Спасибо, и ваш образец действительно полезен! :) - person Sugar; 03.06.2021