2010-01-28 18 views
8

Estoy escuchando cambios de directorio y disco en un proyecto de Cocoa usando FSEvents. Necesito obtener eventos cuando se renombra o borra una carpeta raíz. Por lo tanto, pasé kFSEventStreamCreateFlagWatchRoot al crear el FSEventStream. Pero incluso si elimino o cambio el nombre de la carpeta raíz, no obtendré el correspondiente FSEventStreamEventFlags. Alguna idea de lo que podría ser el problema. Estoy escuchando los cambios en un dispositivo USB montado. Usé ambos FSEventStreamCreate y FSEventStreamCreateRelativeToDevice. Una cosa avisos I es cuando trato con FSEventStreamCreate me sale el siguiente mensaje de error al crear FSEventStream:Cómo escuchar los cambios del sistema de archivos MAC - kFSEventStreamCreateFlagWatchRoot

(CarbonCore.framework) FSEventStreamCreate: watch_all_parents:
error al intentar añadir kqueue para fd 7 (/Volumes/NO NAME; Operación no admitida)

Pero con FSEventStreamCreateRelativeToDevice no hay errores pero todavía no obtiene kFSEventStreamEventFlagRootChanged en indicadores de eventos. Además, durante la creación usando FSEventStreamCreateRelativeToDevice apple dice que si quiero escuchar los cambios de la ruta de acceso, pase la cadena emty "". Pero no puedo escuchar los cambios en la ruta de acceso pasando cadena vacía. Pero cuando paso "/", funciona. Pero incluso para "/" no obtengo ningún FSEventStreamEventFlags apropiado. Estoy pegando el código aquí:

-(void) subscribeFileSystemChanges:(NSString*) path 
{ 
    PRINT_FUNCTION_BEGIN; 

    // if already subscribed then unsubscribe 
    if (stream) 
    { 
     FSEventStreamStop(stream); 
     FSEventStreamInvalidate(stream); /* will remove from runloop */ 
     FSEventStreamRelease(stream); 
    } 

    FSEventStreamContext cntxt = {0}; 
    cntxt.info = self; 

    CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void**)&path, 1, NULL); 


    stream = FSEventStreamCreate(NULL, &feCallback, &cntxt, 
           pathsToWatch, kFSEventStreamEventIdSinceNow, 1, 
           kFSEventStreamCreateFlagWatchRoot); 


    FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), 
            kCFRunLoopDefaultMode); 

    FSEventStreamStart(stream); 


} 

función de retrollamada:

static void feCallback(ConstFSEventStreamRef streamRef, void* pClientCallBackInfo, 
         size_t numEvents, void* pEventPaths, const FSEventStreamEventFlags eventFlags[], 
         const FSEventStreamEventId eventIds[]) 

{ 
char** ppPaths = (char**)pEventPaths; int i; 

    for (i = 0; i < numEvents; i++) 
    { 
     NSLog(@"Event Flags %lu Event Id %llu", eventFlags[i], eventIds[i]); 
     NSLog(@"Path changed: %@", 
       [NSString stringWithUTF8String:ppPaths[i]]); 
    }  
} 

Muchas gracias por adelantado.

+0

No estoy seguro de lo que sucede allí porque nunca he usado FSEvents. Habiendo dicho eso, parece que lo que estás tratando de hacer podría hacerse mejor usando DiskArbitration framework. –

Respuesta

3

que tenía el mismo problema y creo que lo he descubierto. Al parecer kFSEventStreamCreateFlagWatchRoot simplemente se rompe cuando se usa FSEventStreamCreateRelativeToDevice. Tienes que usar FSEventStreamCreate. Dado que la forma anterior es preferible si confía en los id. De eventos históricos, es posible que necesite crear 2 secuencias. Además, tenga en cuenta que parece que no le envían kEventFlagChangedRoot si su aplicación no se está ejecutando, por lo que deberá registrar el directorio cuando se inicie.

3

Creo que el cambio del nombre del volumen no se cuenta como un cambio en el sistema de archivos notificado por FSEvents. Recuerde, el nombre del volumen en sí mismo no existe realmente como una entrada al sistema de archivos. Los que están bajo /Volumes están cocinados por el sistema operativo.

En su lugar, está cubierto por Disk Arbitration.

A continuación se muestra un breve código de muestra. En primer lugar, definir la devolución de llamada

#import <DiskArbitration/DiskArbitration.h> 
void callBack(DADiskRef disk,CFArrayRef keys,void *context) 
{ 
    CFDictionaryRef dict=DADiskCopyDescription(disk); 
    NSString*mountPoint=[(NSDictionary*)dict objectForKey:(NSString*)kDADiskDescriptionVolumePathKey]; 
    NSLog(@"disk at %@:",mountPoint); 
    for(NSString*key in (NSArray*)keys){ 
    NSLog(@"key %@ changed: %@",key,[(NSDictionary*)dict objectForKey:key]);  
    } 
    CFRelease(dict); 
} 

y luego instalar el controlador como este

DASessionRef session=DASessionCreate(NULL); 
DARegisterDiskDescriptionChangedCallback(session, NULL, NULL, callBack, NULL); 
DASessionScheduleWithRunLoop(session, [[NSRunLoop currentRunLoop] getCFRunLoop], kCFRunLoopCommonModes); 
+0

HI Gracias por la respuesta. Pero estoy más buscando una solución con FSEVENTS porque lo que realmente me molesta es que incluso si doy la ruta de acceso "/" o cualquier subdirectorio y luego lo elimino o cambio de nombre, no recibo los indicadores de eventos adecuados en la devolución de llamada. He pegado el código en la pregunta. Otra pregunta, ¿dónde obtengo la referencia completa de Arbitration de disco porque no sé qué teclas debería mirar o mirar, etc.O bien, ¿dónde encuentras la explicación de kDADiskDescriptionVolumePathKey o kDADiskDescriptionWatchVolumeName? – wantro

+0

Las claves se pueden encontrar en http://developer.apple.com/mac/library/documentation/Darwin/Reference/DiscArbitrationFramework/index.html ... Bueno, usted sabe que hay un cuadro de búsqueda en el sitio web de ADC, a la derecha ? ¿Buscó la constante allí? Déjame pensar en tu primera pregunta. – Yuji

+0

Copié y pegué su código, y funcionó en mi máquina (10.6.2). ¿Podría publicar su rutina de devolución de llamada, y cómo está revisando los indicadores de eventos devueltos? – Yuji

Cuestiones relacionadas