Cocoa Monitor a file for modifications

2019-01-18 07:51发布

问题:

I have a file path to a specific file and I want to register to be notified whenever that file changes (its contents have been modified).

I have tried searching google and I can't find a clear answer. I have experimented with kqueue and NSWorkspace but have not had much success.

What is the proper way to do this?

Thanks!

回答1:

I am using VDKQueue right now - author says it's a refactored and more performant version of UKKQueue.

Implementation was pretty straightforward:

  • let your controller be the VDKQueueDelegate;
  • declare a VDKQueue* ivar / property;
  • setup delegate method VDKQueue:receivedNotification:forPath:;
  • init the queue and set its delegate to the controller itself;
  • add resources to watch with addPath:notifyingAbout:.

Then just do your business in the delegate method.



回答2:

Thanks to a blog post from David Hamerick, I finally managed to detect any modification on a file:

+ (void)monitorFile:(NSString*) path {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    int fildes = open([path UTF8String], O_EVTONLY);

    __block typeof(self) blockSelf = self;
    __block dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fildes,
               DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | 
               DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_LINK | DISPATCH_VNODE_RENAME | 
               DISPATCH_VNODE_REVOKE, queue);
    dispatch_source_set_event_handler(source, ^{
                                          unsigned long flags = dispatch_source_get_data(source);
                                          if(flags & DISPATCH_VNODE_DELETE)
                                          {
                                              dispatch_source_cancel(source);
                                              //        
                                              // DO WHAT YOU NEED HERE
                                              //
                                              [blockSelf monitorFile:path];
                                          }
                                      });
    dispatch_source_set_cancel_handler(source, ^(void) {
                                          close(fildes);
                                      });
    dispatch_resume(source);
}