2013-08-24 31 views
13

我正在看文件系统事件的目录。除了一个例外,一切似乎都正常。当我第一次创建一个文件时,它吐出它创建的文件。然后我可以删除它,并说它已被删除。当我再次创建相同的文件时,我同时获得了创建和删除的标志。我显然误解了回调被调用时标记的设置方式。这里发生了什么?OSX FSEventStreamEventFlags无法正常工作

// 
// 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; 
} 
+0

类似问题:https://github.com/haskell-fswatch/hfsnotify/issues/36 –

+1

从你的回调代码中,我看不出你可以同时删除和创建的任何方式。他们必须分开回调打印。 (你有if()else if()。) –

+0

你测试了'kFSEventStreamCreateFlagNoDefer'标志的移除是否改变了任何东西吗? – JSuar

回答

6

据我所知,你将不得不寻找任何kFSEventStreamEventFlagItemRemovedkFSEventStreamEventFlagItemCreated,然后用stat()或类似的检查,如果在事实被添加或删除的文件。 FSEvents文档似乎暗示。

它看起来像API是or'ing事件位在一起...所以真正它是自FSEventsListener创建以来所做的所有更改的OR。由于这似乎是这种情况,另一种选择可能是每次创建一个新的FSEventListener(并使用coalesce timer选项)。

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

我以前使用过的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; 
} 
+0

谢谢!我喜欢使用kqueue的想法 - 不知道它适用于Mac OS X. –