2010-01-28 3 views
8

Я слушаю изменения каталога и диска в проекте Cocoa с использованием FSEvents. Мне нужно получить события, когда корневая папка переименована или удалена. Итак, я прошел kFSEventStreamCreateFlagWatchRoot при создании FSEventStream. Но даже если я удалю или переименую корневую папку, я не получаю соответствующий FSEventStreamEventFlags. Любая идея, что может быть проблемой. Я слушаю изменения на USB-устройстве. Я использовал оба FSEventStreamCreate и FSEventStreamCreateRelativeToDevice. Одна вещь, которую я замечает, когда я пытаюсь с FSEventStreamCreate я получаю следующее сообщение об ошибке при создании FSEventStream:Как прослушивать изменения файловой системы MAC-kFSEventStreamCreateFlagWatchRoot

(CarbonCore.framework) FSEventStreamCreate: watch_all_parents:
ошибка при попытке добавить Kqueue для fd 7 (/Volumes/NO NAME, операция не поддерживается)

Но с FSEventStreamCreateRelativeToDevice ошибок не найдено, но все равно не получается kFSEventStreamEventFlagRootChanged в флагах событий. Кроме того, в то время как создание с использованием FSEventStreamCreateRelativeToDevice apple say's, если я хочу прослушивать изменения корневого пути, передает emty string "". Но я не могу слушать изменения корневого пути, передавая пустую строку. Но когда я прохожу "/", он работает. Но даже для "/" у меня нет должного FSEventStreamEventFlags. Я вставить код здесь:

-(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); 


} 

назад Вызов функции:

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]]); 
    }  
} 

Спасибо большое заранее.

+0

Я не уверен, что там не так, потому что я никогда не использовал FSEvents. Сказав это, похоже, что то, что вы пытаетесь сделать, может быть лучше сделано с использованием инфраструктуры DiskArbitration. –

ответ

3

Я была такая же проблема, и я думаю, что я понял это. По-видимому kFSEventStreamCreateFlagWatchRoot просто просто разоряется при использовании FSEventStreamCreateRelativeToDevice. Вы должны использовать FSEventStreamCreate. Поскольку прежняя форма предпочтительнее, если вы полагаетесь на исторические идентификаторы событий, вам может потребоваться создать 2 потока. Также обратите внимание, что вы не получаете kEventFlagChangedRoot, если ваше приложение не работает, поэтому вам нужно будет установить каталог при запуске.

3

Я думаю, что изменение имени тома не считается изменением файловой системы, сообщенной FSEvents. Помните, что само имя тома не существует как запись в файловой системе. ОС под /Volumes.

Вместо этого он покрыт Disk Arbitration.

Ниже приводится короткий образец кода. Во-первых, определите функцию обратного вызова

#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); 
} 

, а затем установить обработчик как этот

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

HI Спасибо за ответ. Но я больше ищу решение с FSEVENTS, потому что меня действительно беспокоит то, что даже если я даю корневой путь «/» или любые подкаталоги, а затем удаляю или переименовываю его, я не получаю правильные флаги событий в обратном вызове. Я вставил код в вопрос. Еще один вопрос, где я могу получить полную информацию о дисковой арбитраже, потому что я не знаю, какие ключи я должен искать или смотреть и т. Д.Или настойчивость, где вы планируете объяснение kDADiskDescriptionVolumePathKey или kDADiskDescriptionWatchVolumeName. – wantro

+0

Ключи можно найти по адресу http://developer.apple.com/mac/library/documentation/Darwin/Reference/DiscArbitrationFramework/index.html ... Ну, вы знаете, что на веб-сайте АЦП есть окно поиска, справа ? Вы искали постоянную там? Позвольте мне подумать о вашем первом вопросе. – Yuji

+0

Я скопировал и вставил ваш код, и он работал на моей машине (10.6.2). Могли бы вы опубликовать свою процедуру обратного вызова и как вы проверяете возвращаемые флаги событий? – Yuji

Смежные вопросы