2013-08-24 5 views
13

ファイルシステムイベントのディレクトリを監視しています。 1つの例外を除いてすべてがうまくいくようです。私が最初にファイルを作成すると、それが作成されたことが分かります。それから私はそれを取り除くことができ、それは削除されたと言います。同じファイルを再び作成すると、同時に作成されたフラグと削除されたフラグが取得されます。私は明らかにコールバックが呼び出されているときにどのようにフラグがセットされているのか誤解しています。ここで何が起きてるの?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の作成以降に行われたすべての変更の論理和です。それがそうであるように思われるので、別のオプションは毎回新しいFSEventListenerを作成することです(そしてcoalesceタイマーオプションを使用します)。

私はいくつかのグーグルをしましたが、この問題の他の例やりんごのサンプルコードを見つけられませんでしたが、あまりにも長い時間をかけていませんでした。私は以前に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上で動作するのか分かりませんでした。 –

関連する問題