如何监听文件系统更改MAC-kFSEventStreamCreateFlagWatchRoot

时间:2010-01-28 13:39:49

标签: cocoa fsevents

我正在使用FSEvents在Cocoa项目中监听目录和磁盘更改。我需要在重命名或删除根文件夹时获取事件。所以,我在创建kFSEventStreamCreateFlagWatchRoot时通过FSEventStream。但即使我删除或重命名根文件夹,我也没有得到相应的FSEventStreamEventFlags。知道可能是什么问题。我正在听USB安装设备的更改。我同时使用了FSEventStreamCreateFSEventStreamCreateRelativeToDevice。我注意到的一件事是当我尝试FSEventStreamCreate时,我在创建FSEventStream时收到以下错误消息:

  

CarbonCore.frameworkFSEventStreamCreatewatch_all_parents
  尝试为fd 7添加kqueue时遇到错误(/Volumes/NO NAME;操作不受支持)

但是FSEventStreamCreateRelativeToDevice使用kFSEventStreamEventFlagRootChanged没有错误,但仍未在事件标志中获得FSEventStreamCreateRelativeToDevice。此外,使用"" apple说明如果我想听取根路径更改,则传递emty字符串"/"。但是我无法通过传递空字符串来监听根路径更改。但是当我通过"/"时它就有效了。但即使是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]]); 
    }    
}

回叫功能:

{{1}}

提前多多感谢。

2 个答案:

答案 0 :(得分: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);

答案 1 :(得分:3)

我有同样的问题,我想我想出来了。显然kFSEventStreamCreateFlagWatchRoot只是在使用FSEventStreamCreateRelativeToDevice时被破坏了。您必须使用FSEventStreamCreate。如果您依赖于历史事件ID,那么前一种形式是首选,您可能需要创建两个流。此外,请注意,如果您的应用未运行,您似乎没有收到kEventFlagChangedRoot,因此您需要在启动时统计目录。