【问题标题】:OSX FSEventStreamEventFlags not working correctlyOSX FSEventStreamEventFlags 无法正常工作
【发布时间】:2013-08-24 05:33:02
【问题描述】:

我正在监视文件系统事件的目录。除了一个例外,一切似乎都运行良好。当我第一次创建文件时,它会吐出它已创建。然后我可以删除它,它说它已被删除。当我再次创建同一个文件时,我同时得到一个创建和删除标志。我显然误解了在调用回调时如何设置标志。这里发生了什么?

//
//  main.c
//  GoFSEvents
//
//  Created by Kyle Cook on 8/22/13.
//  Copyright (c) 2013 Kyle Cook. All rights reserved.
//

#include <CoreServices/CoreServices.h>
#include <stdio.h>
#include <string.h>

void eventCallback(FSEventStreamRef stream, void* callbackInfo, size_t numEvents, void* paths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) {
    char **pathsList = paths;

    for(int i = 0; i<numEvents; i++) {
        uint32 flag = eventFlags[i];

        uint32 created = kFSEventStreamEventFlagItemCreated;
        uint32 removed = kFSEventStreamEventFlagItemRemoved;

        if(flag & removed) {
            printf("Item Removed: %s\n", pathsList[i]);
        }
        else if(flag & created) {
            printf("Item Created: %s\n", pathsList[i]);
        }
    }
}

int main(int argc, const char * argv[])
{
    CFStringRef mypath = CFSTR("/path/to/dir");
    CFArrayRef paths = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL);

    CFRunLoopRef loop = CFRunLoopGetMain();
    FSEventStreamRef stream = FSEventStreamCreate(NULL, (FSEventStreamCallback)eventCallback, NULL, paths, kFSEventStreamEventIdSinceNow, 1.0, kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagNoDefer);
    FSEventStreamScheduleWithRunLoop(stream, loop, kCFRunLoopDefaultMode);
    FSEventStreamStart(stream);

    CFRunLoopRun();

    FSEventStreamStop(stream);
    FSEventStreamInvalidate(stream);
    FSEventStreamRelease(stream);

    return 0;
}

【问题讨论】:

  • 从您的回调代码中,我看不出有任何方法可以同时删除和创建。它们必须在单独的回调中打印。 (你有 if () else if ()。)
  • 您是否测试过删除kFSEventStreamCreateFlagNoDefer 标志是否有任何改变?
  • 我得到了同样的行为......以前我使用过 kqueue:gist.github.com/nielsbot/5155671 也许这很有帮助。

标签: c macos core-foundation fsevents


【解决方案1】:

据我所知,您必须查找kFSEventStreamEventFlagItemRemovedkFSEventStreamEventFlagItemCreated,然后使用stat() 或类似方法来检查文件是否确实被添加或删除。 FSEvents 文档似乎暗示了这一点。

看起来 API 将事件位组合在一起...所以实际上它是自创建 FSEventsListener 以来所做的所有更改的 OR。既然情况似乎如此,另一种选择可能是每次都创建一个新的 FSEventListener(并使用合并计时器选项)。

我做了一些谷歌搜索,但没有找到这个问题的其他示例甚至苹果示例代码,但我没有花太长时间。

我之前使用过 kqueue API:https://gist.github.com/nielsbot/5155671(这个要点是 kqueue 的 obj-c 包装器)

我更改了您的示例代码以显示为每个 FSEvent 设置的所有标志:

#include <CoreServices/CoreServices.h>
#include <stdio.h>
#include <string.h>

static int __count = 0 ;
void eventCallback(FSEventStreamRef stream, void* callbackInfo, size_t numEvents, void* paths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) {
    char **pathsList = paths;

    printf("callback #%u\n", ++__count ) ;
    const char * flags[] = {
        "MustScanSubDirs",
        "UserDropped",
        "KernelDropped",
        "EventIdsWrapped",
        "HistoryDone",
        "RootChanged",
        "Mount",
        "Unmount",
        "ItemCreated",
        "ItemRemoved",
        "ItemInodeMetaMod",
        "ItemRenamed",
        "ItemModified",
        "ItemFinderInfoMod",
        "ItemChangeOwner",
        "ItemXattrMod",
        "ItemIsFile",
        "ItemIsDir",
        "ItemIsSymlink",
        "OwnEvent"
    } ;

    for(int i = 0; i<numEvents; i++)
    {
        printf("%u\n", i ) ;
        printf("\tpath %s\n", pathsList[i]) ;
        printf("\tflags: ") ;
        long bit = 1 ;
        for( int index=0, count = sizeof( flags ) / sizeof( flags[0]); index < count; ++index )
        {
            if ( ( eventFlags[i] & bit ) != 0 )
            {
                printf("%s ", flags[ index ] ) ;
            }
            bit <<= 1 ;
        }
        printf("\n") ;
    }

    FSEventStreamFlushSync( stream ) ;

}

int main(int argc, const char * argv[])
{
    CFStringRef path = CFStringCreateWithCString( kCFAllocatorDefault, argv[1], kCFStringEncodingUTF8 ) ;
    CFArrayRef paths = CFArrayCreate(NULL, (const void **)&path, 1, &kCFTypeArrayCallBacks );
    if ( path ) { CFRelease( path ) ; }

    CFRunLoopRef loop = CFRunLoopGetCurrent() ;
    FSEventStreamRef stream = FSEventStreamCreate(NULL, (FSEventStreamCallback)eventCallback, NULL, paths, kFSEventStreamEventIdSinceNow, 0, kFSEventStreamCreateFlagFileEvents );
    if ( paths ) { CFRelease( paths ) ; }

    FSEventStreamScheduleWithRunLoop(stream, loop, kCFRunLoopDefaultMode);
    FSEventStreamStart(stream);

    CFRunLoopRun() ;

    FSEventStreamStop(stream);
    FSEventStreamInvalidate(stream);
    FSEventStreamRelease(stream);

    return 0;
}

【讨论】:

  • 谢谢!我喜欢使用 kqueue 的想法——不知道它可以在 Mac OS X 上运行。
猜你喜欢
  • 2013-02-18
  • 2023-04-01
  • 1970-01-01
  • 2014-08-18
  • 1970-01-01
  • 2011-07-01
  • 1970-01-01
  • 2016-12-01
  • 2014-08-26
相关资源
最近更新 更多