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

Cocoa 如何侦听文件系统更改MAC-kFSEventStreamCreateFlagWatchRoot,cocoa,fsevents,Cocoa,Fsevents,我正在使用FSEvents监听Cocoa项目中的目录和磁盘更改。我需要在根文件夹被重命名或删除时获取事件。因此,在创建FSEventStream时,我通过了kFSEventStreamCreateFlagWatchRoot。但是,即使删除或重命名根文件夹,也不会得到相应的FSEventStreamEventFlags。你知道可能是什么问题吗。我正在侦听USB安装设备中的更改。我使用了FSEventStreamCreate和FSEventStreamCreateRelativeToDevice。我

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

CarbonCore.framework
FSEventStreamCreate
watch\u all\u parents

尝试为
fd 7
添加kqueue时出错(
/Volumes/NO NAME
;不支持操作)

但是使用
FSEventStreamCreateRelativeToDevice
时,没有错误,但仍然没有在事件标志中获取
kfseventstreamventflagrootchanged
。另外,在使用
FSEventStreamCreateRelativeToDevice
apple say创建时,如果我想监听根路径更改,请传递emty string
”。但我无法通过传递空字符串来侦听根路径的更改。但是当我通过
“/”
时,它就起作用了。但即使对于
“/”
我也没有得到任何适当的
fseventstreamventflags
。我在这里粘贴代码:

-(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]]); 
    }    
}
静态void feCallback(ConstFSEventStreamRef streamRef,void*pClientCallBackInfo,
大小\u t numEvents,void*peventPath,const fseventStreamventFlags eventFlags[],
常量fseventstreamventid eventIds[]
{
字符**路径=(字符**)路径;
对于(i=0;i

提前非常感谢。

我认为卷名的更改不算作FSEvents报告的文件系统更改。请记住,卷名本身实际上并不作为文件系统条目存在。
/Volumes
下的内容是由操作系统编写的

相反,它被覆盖了

下面是一个简短的示例代码。首先,定义回调函数

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

我也有同样的问题,我想我已经解决了。显然,当使用
FSEventStreamCreateRelativeToDevice
时,kFSEventStreamCreateFlagWatchRoot
只是简单地被破坏了。您必须使用
FSEventStreamCreate
。由于如果依赖历史事件ID,则前一种形式更可取,因此可能需要创建2个流。另外,请注意,如果您的应用程序未运行,您似乎不会收到发送给您的
kEventFlagChangedRoot
,因此您需要在启动时统计目录。

您好,谢谢您的回答。但我更喜欢用FSEVENTS寻找解决方案,因为真正困扰我的是,即使我给出根路径“/”或任何子目录,然后删除或重命名它,我也无法在回调中获得正确的事件标志。我已在问题中粘贴了代码。还有一个问题,由于我不知道应该查看或查看哪些键,所以我从何处获得磁盘arbition的完整参考。或者,简而言之,您从何处获得KDadiskDescriptionVolumeThkey或kDADiskDescriptionWatchVolumeName的解释。这些键可以在。。。你知道ADC网站上有一个搜索框,对吧?你在那里搜索常数了吗?让我想想你的第一个问题。我复制并粘贴了你的代码,它在我的机器上运行(10.6.2)。您可以发布您的回调例程,以及如何检查返回的事件标志吗?非常感谢您的回答。我还添加了回调功能。我正在使用10.5.8这可能是原因吗?好的,我启动到10.5.8并检查它是否工作。我所做的是观看
/tmp/boo
,然后观看
mv/tmp/boo/tmp/bar
。FSEvents正确地为我提供了事件标志
0x20
。你到底做了什么?我不确定那里出了什么问题,因为我从未使用过FSEvents。话虽如此,听起来使用DiskArbitration framework可能会更好。
DASessionRef session=DASessionCreate(NULL);
DARegisterDiskDescriptionChangedCallback(session, NULL, NULL, callBack, NULL);
DASessionScheduleWithRunLoop(session, [[NSRunLoop currentRunLoop] getCFRunLoop], kCFRunLoopCommonModes);