2010-07-05 12 views

Répondre

23

This thread sur les forums Apple Developer peut être intéressant, dans lequel il est suggéré que vous exécutez un kqueue dans son propre thread, le suivi du dossier Documents de l'application.

Une technologie d'Apple a suivi avec une sample code here:

- (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); 
} 
+0

Fonctionne un régal! Merci Alex. –

+4

Vous devrez inclure ces en-têtes: '#include #include #include #include #include ' – Dustin

+1

si je veux quand le moniteur et trouver des fichiers dans le dossier documents appel certaine fonction, aussi où je mets ces trois fonctions, dans la classe appdelegate ou quoi – AMH

4

question ancienne, mais je suis tombé sur this Apple code qui comprend un moniteur de répertoire. Notez qu'il déclenche le moment où un fichier est ajouté (ou supprimé); Cela pourrait être avant que l'OS ait fini d'écrire dans le fichier.

+0

+1 Cela m'a aidé! – ZYiOS

+1

Comment attendre que le fichier ait été écrit complètement, car il se déclenche trop tôt et quand j'y accède, je reçois un SIGABRT. – jarryd

13

est ici une solution de rechange à l'aide Grand Central Dispatch (GCD) qui vous permet de recevoir des notifications de modification de fichier de NSNotificationCenter:

Ajouter ces variables à l'interface de la classe:

// Dispatch queue 
dispatch_queue_t _dispatchQueue; 

// A source of potential notifications 
dispatch_source_t _source; 

Ajoutez le code suivant à la mise en œuvre:

#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!"); 
    }]; 
+0

merci beaucoup !! Simple et fonctionne parfaitement. – Ravi