【问题标题】:Is it possible to use FSEvents to get notifications that a folder has been moved?是否可以使用 FSEvents 获取文件夹已移动的通知?
【发布时间】:2011-04-27 03:28:12
【问题描述】:

我正在使用 FSEvents API 来获取我正在跟踪的本地目录中的更改通知。

是否有可能使用 FSEvents 或其他任何方法获得监视目录已移动到磁盘上另一个位置的通知?

更新:

这是我到目前为止的代码,我现在正在尝试使用带有 FSEventStreamCreate 的 kFSEventStreamCreateFlagWatchRoot 标志来获取根更改通知,到目前为止没有成功。

- (void)registerForFileSystemNotifications {

    NSString *watchedDirectoryPath = [[NSUserDefaults standardUserDefaults] valueForKey:kMyWatchedDirectoryPathKey];
    self.watchedDirectoryFileDescriptor = open([watchedDirectoryPath cStringUsingEncoding:NSUTF8StringEncoding], O_RDONLY);

    NSArray *paths = [NSArray arrayWithObject:watchedDirectoryPath];
    void *appController = (void *)self;
    FSEventStreamContext context = {0, appController, NULL, NULL, NULL};
    FSEventStreamRef streamRef = FSEventStreamCreate(NULL, 
                                                     &fsevents_callback, 
                                                     &context, 
                                                     (CFArrayRef) paths, 
                                                     kFSEventStreamEventIdSinceNow, 
                                                     (CFTimeInterval)2.0, 
                                                     kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagWatchRoot);

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

}

void fsevents_callback(ConstFSEventStreamRef streamRef, 
                       void *userData, 
                       size_t numumberOfEvents, 
                       void *eventPaths, 
                       const FSEventStreamEventFlags eventFlags[], 
                       const FSEventStreamEventId eventIds[]) {

    MyAppController *appController = (MyAppController *)userData;   
    char *newPath = calloc(4096, sizeof(char));
    int pathIntPointer = (int)newPath;

    int length = fcntl(appController.watchedDirectoryFileDescriptor, F_GETPATH, pathIntPointer);

    NSString *newPathString = [[NSString alloc] initWithBytes:newPath length:(NSUInteger)length encoding:NSUTF8StringEncoding];
    NSLog(@"newPathString: %@", newPathString); // empty
}

【问题讨论】:

    标签: cocoa fsevents


    【解决方案1】:

    是的。将kFSEventStreamCreateFlagWatchRoot 作为最后一个参数传递给FSEventStreamCreate,如果目录被移动或重命名,您将收到通知。来自docs

    请求通知您正在观看的路径沿途的更改。例如,使用此标志,如果您观看“/foo/bar”并将其重命名为“/foo/bar.old”,您将收到 RootChanged 事件。如果目录“/foo”被重命名,也是如此。您收到的事件是一个特殊事件:事件的路径是您指定的原始路径,设置了标志 kFSEventStreamEventFlagRootChanged 并且事件 ID 为零。 RootChanged 事件可用于指示您应该重新扫描特定层次结构,因为它已完全更改(与其中的内容更改相反)。如果你想跟踪一个目录的当前位置,最好在创建流之前打开目录,这样你就有一个文件描述符,可以发出 F_GETPATH fcntl() 来找到当前路径。

    编辑:添加 fcntl 示例

    那个 cocoadev 的例子表明作者对指针有点缺乏经验。 pathIntPointer 不仅是不必要的,它也是你的问题的原因。从 fnctl 对返回码的错误检查会发现它。这是您的回调的修订版本:

    void fsevents_callback(ConstFSEventStreamRef streamRef, 
                       void *userData, 
                       size_t numumberOfEvents, 
                       void *eventPaths, 
                       const FSEventStreamEventFlags eventFlags[], 
                       const FSEventStreamEventId eventIds[]) {
    
        MyAppController *appController = (MyAppController *)userData;   
        char newPath[ MAXPATHLEN ];
        int rc;
    
        rc = fcntl( appController.watchedDirectoryFileDescriptor, F_GETPATH, newPath );
        if ( rc == -1 ) {
            perror( "fnctl F_GETPATH" );
            return;
        }
    
        NSString *newPathString = [[NSString alloc] initWithUTF8String: newPath ];
        NSLog(@"newPathString: %@", newPathString);
        [ newPathString release ];
    }
    

    【讨论】:

    • 谢谢!我现在正在尝试这个,但到目前为止没有任何运气。我已将现有代码添加到问题中。我能找到的使用 F_GETPATH 的唯一示例是 cocoadev.com/index.pl?DescriptorToPath。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多