方法一:
- (void)kqueueFired { int kq; struct kevent event; struct timespec timeout = { 0, 0 }; int eventCount; kq = CFFileDescriptorGetNativeDescriptor(self->_kqRef); assert(kq >= 0); eventCount = kevent(kq, NULL, 0, &event, 1, &timeout); assert( (eventCount >= 0) && (eventCount < 2) ); if (eventCount == 1) { NSLog(@"dir changed"); } CFFileDescriptorEnableCallBacks(self->_kqRef, kCFFileDescriptorReadCallBack); } static void KQCallback(CFFileDescriptorRef kqRef, CFOptionFlags callBackTypes, void *info) { ViewController * obj; obj = (ViewController *) info; assert([obj isKindOfClass:[ViewController class]]); assert(kqRef == obj->_kqRef); assert(callBackTypes == kCFFileDescriptorReadCallBack); [obj kqueueFired]; } - (IBAction)testAction:(id)sender { #pragma unused(sender) NSString * docPath; int dirFD; int kq; int retVal; struct kevent eventToAdd; CFFileDescriptorContext context = { 0, self, NULL, NULL, NULL }; CFRunLoopSourceRef rls; docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; assert(docPath != 0); NSLog(@"%@", docPath); dirFD = open([docPath fileSystemRepresentation], O_EVTONLY); assert(dirFD >= 0); kq = kqueue(); assert(kq >= 0); eventToAdd.ident = dirFD; eventToAdd.filter = EVFILT_VNODE; eventToAdd.flags = EV_ADD | EV_CLEAR; eventToAdd.fflags = NOTE_WRITE; eventToAdd.data = 0; eventToAdd.udata = NULL; retVal = kevent(kq, &eventToAdd, 1, NULL, 0, NULL); assert(retVal == 0); assert(self->_kqRef == NULL); self->_kqRef = CFFileDescriptorCreate(NULL, kq, true, KQCallback, &context); assert(self->_kqRef != NULL); rls = CFFileDescriptorCreateRunLoopSource(NULL, self->_kqRef, 0); assert(rls != NULL); CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); CFRelease(rls); CFFileDescriptorEnableCallBacks(self->_kqRef, kCFFileDescriptorReadCallBack); }
方法二:
// Dispatch queue dispatch_queue_t _dispatchQueue; // A source of potential notifications dispatch_source_t _source; #define fileChangedNotification @"fileChangedNotification" // Get the path to the home directory NSString * homeDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; // Create a new file descriptor - we need to convert the NSString to a char * i.e. C style string int filedes = open([homeDirectory cStringUsingEncoding:NSASCIIStringEncoding], O_EVTONLY); // Create a dispatch queue - when a file changes the event will be sent to this queue _dispatchQueue = dispatch_queue_create("FileMonitorQueue", 0); // Create a GCD source. This will monitor the file descriptor to see if a write command is detected // The following options are available /*! * @typedef dispatch_source_vnode_flags_t * Type of dispatch_source_vnode flags * * @constant DISPATCH_VNODE_DELETE * The filesystem object was deleted from the namespace. * * @constant DISPATCH_VNODE_WRITE * The filesystem object data changed. * * @constant DISPATCH_VNODE_EXTEND * The filesystem object changed in size. * * @constant DISPATCH_VNODE_ATTRIB * The filesystem object metadata changed. * * @constant DISPATCH_VNODE_LINK * The filesystem object link count changed. * * @constant DISPATCH_VNODE_RENAME * The filesystem object was renamed in the namespace. * * @constant DISPATCH_VNODE_REVOKE * The filesystem object was revoked. */ // Write covers - adding a file, renaming a file and deleting a file... _source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,filedes, DISPATCH_VNODE_WRITE, _dispatchQueue); // This block will be called when teh file changes dispatch_source_set_event_handler(_source, ^(){ // We call an NSNotification so the file can change can be detected anywhere [[NSNotificationCenter defaultCenter] postNotificationName:fileChangedNotification object:Nil]; }); // When we stop monitoring the file this will be called and it will close the file descriptor dispatch_source_set_cancel_handler(_source, ^() { close(filedes); }); // Start monitoring the file... dispatch_resume(_source); //... // When we want to stop monitoring the file we call this //dispatch_source_cancel(source); // To recieve a notification about the file change we can use the NSNotificationCenter [[NSNotificationCenter defaultCenter] addObserverForName:fileChangedNotification object:Nil queue:Nil usingBlock:^(NSNotification * notification) { NSLog(@"File change detected!"); }];