2

I want to create a simple event stream in order to listen events when some changes ocurre in a directory. The first step is the creation of the stream, but I receive an error in the creation using FSEventStreamCreate function. Googling this error was useless, I can not understand where is the error.

(CarbonCore.framework) FSEventStreamCreate: _FSEventStreamCreate: ERROR: (CFStringGetTypeID() != CFGetTypeID(cfStringRef)) (i = 0)

My code is quite similar to the one present in the apple documentation

Anyway, this is my code:

static void gotEvent(ConstFSEventStreamRef stream, 
                 void *clientCallBackInfo, 
                 size_t numEvents, 
                 void *eventPathsVoidPointer, 
                 const FSEventStreamEventFlags eventFlags[], 
                 const FSEventStreamEventId eventIds[]
                 ) {

    NSLog(@"File Changed!");
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    NSString *fileInputPath = @"/tmp/mamma/ciao.txt";
    FSEventStreamRef stream = [self eventStreamForFileAtPath: fileInputPath];
}

- (FSEventStreamRef) eventStreamForFileAtPath: (NSString *) fileInputPath
{
    if (![[NSFileManager defaultManager] fileExistsAtPath:fileInputPath]) {
        @throw [NSException exceptionWithName: @"FileNotFoundException"
                                   reason:@"There is not file at path specified in fileInputPath"
                                 userInfo: nil];
    }
    CFStringRef fileInputDir = (CFStringRef)[fileInputPath stringByDeletingLastPathComponent];
    CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **) fileInputDir, 1, NULL);
    void *callbackInfo = NULL;
    CFAbsoluteTime latency = 3.0; /* Latency in seconds */

    FSEventStreamRef stream = FSEventStreamCreate(
                                                 NULL, 
                                                 &gotEvent, 
                                                 callbackInfo, 
                                                 pathsToWatch, 
                                                 kFSEventStreamEventIdSinceNow, 
                                                 latency, 
                                                 kFSEventStreamEventFlagNone
                                                 );

    return stream;
}
Giuseppe
  • 6,666
  • 2
  • 20
  • 32

1 Answers1

3

Try this code instead:

- (FSEventStreamRef) eventStreamForFileAtPath: (NSString *) fileInputPath  {

   if (![[NSFileManager defaultManager] fileExistsAtPath:fileInputPath]) {
       @throw [NSException exceptionWithName:@"FileNotFoundException"
                                      reason:@"There is not file at path specified in fileInputPath"
                                    userInfo:nil];
   }

   NSString *fileInputDir = [fileInputPath stringByDeletingLastPathComponent];

   NSArray *pathsToWatch = [NSArray arrayWithObjects:fileInputDir, nil];

   void *appPointer = (void *)self;

   FSEventStreamContext context = {0, appPointer, NULL, NULL, NULL};

   NSTimeInterval latency = 3.0;

   FSEventStreamRef stream = FSEventStreamCreate(NULL,
                                                  &gotEvent,                                 
                                                  &context,                                 
                                                  (CFArrayRef) pathsToWatch,                                 
                                                  kFSEventStreamEventIdSinceNow,                                 
                                                  (CFAbsoluteTime) latency,                                 
                                                  kFSEventStreamCreateFlagUseCFTypes                                 
                                                  );

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

   return stream;

}

Also take a look at this link: Monitoring File Changes with the File System Events API. It shows you how to monitor file changes in your Cocoa application.

ms83
  • 1,804
  • 16
  • 13
  • With your code I finally receive a valid stream object. I can't understand exactly why your code work and mine not! The only difference I see is that you are casting NSArray instead of create directly a CFArrayRef. You have also a different context, but it seems not to be influent for the creation of the stream – Giuseppe Oct 13 '11 at 11:25
  • Your method would work, its just that you forgot to put a reference operator(&) before `fileInputDir` in the `CFArrayCreate` function. I also don't see you calling `FSEventStreamScheduleWithRunLoop()` or `FSEventStreamStart()`. You should also read through the link I provided, it will show you how to stop and invalidate the stream once your finished. – ms83 Oct 13 '11 at 20:12
  • The problem was on the creation of the array. FSEventStreamScheduleWithRunLoop() and FSEventStreamStart() were present in another part of the code. Thanks for your help – Giuseppe Oct 13 '11 at 20:28
  • Any Idea on how to detect type of folder event raised in the folder in the callback method? Ex: File Renamed, File Created etc? – Ramaprasad Upadhyaya Feb 28 '14 at 07:25
  • Set kFSEventStreamCreateFlagFileEvents when you create your event stream. This will send FSEventStreamEventFlags file events to your callback function. One thing to note is the event bits will be OR'ed together. Take a look at this http://stackoverflow.com/questions/18415285/osx-fseventstreameventflags-not-working-correctly to figure out the OR'ed event flags. – ms83 Mar 03 '14 at 09:41
  • 1
    For anyone coming across this answer now (like I did), it appears the relevant link is now: https://developer.apple.com/library/content/documentation/Darwin/Conceptual/FSEvents_ProgGuide/Introduction/Introduction.html – Dave Nottage Jul 14 '17 at 21:50