2010-07-05 11 views

Respuesta

23

This thread en los Foros de desarrolladores de Apple pueden ser de su interés, en el que se sugiere que ejecute un kqueue en su propio hilo, siguiendo la carpeta Documentos de la aplicación.

Una Manzana tecnología siguió con algunos 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

Works a treat! Gracias Alex. –

+4

Tendrá que incluir estos encabezados: '# include # include # include # include # include ' – Dustin

+1

lo que si quiero cuando el monitor y encontrar archivos en la llamada carpeta de documentos determinada función, también donde puse esas tres funciones, en la clase de delegado de aplicaciones o qué – AMH

4

vieja pregunta, pero me encontré con this Apple code que incluye un monitor de directorio. Tenga en cuenta que se activa en el momento en que se agrega (o elimina) un archivo; esto podría ser antes de que el sistema operativo haya completado la escritura en el archivo.

+0

+1 ¡Esta ayuda para mí! – ZYiOS

+1

¿Cómo se espera hasta que el archivo se haya escrito por completo, porque se dispara temprano y cuando lo tengo obtengo un SIGABRT? – jarryd

13

Aquí es una solución alternativa utilizando Grand Central Dispatch (GCD) que le permite recibir notificaciones de cambio de archivo de NSNotificationCenter:

Añadir estas variables a la interfaz de la clase:

// Dispatch queue 
dispatch_queue_t _dispatchQueue; 

// A source of potential notifications 
dispatch_source_t _source; 

Agregue el código siguiente para la implementación:

#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

muchas gracias! Simple y funciona perfecto. – Ravi

Cuestiones relacionadas