【问题标题】:iTunes File Sharing app: realtime monitoring for incoming datasiTunes 文件共享应用程序:实时监控传入数据
【发布时间】:2012-03-16 03:39:54
【问题描述】:

我正在开发支持 iTunes 文件共享功能的 iOS 项目。目标是实时跟踪传入/更改的数据。

我正在使用 Apple 示例代码中的 (有点修改) DirectoryWatcher 类 也试过this source code

数据是 NSBundle (*.bundle),一些包在 100-500 MB 范围内,取决于其内容,一些视频/音频内容。捆绑包中包含基于 xml 的描述符文件。

问题是上述代码中的任何一个触发通知或在数据刚刚开始复制时而不是在复制/更改/删除过程完全完成时

接下来尝试:

检查文件属性:

NSDictionary *fileAttrs = [[NSFileManager defaultManager] attributesOfItemAtPath:[contURL path] error:nil];
BOOL fileBusy = [[fileAttrs objectForKey:NSFileBusy] boolValue];

寻找fileSize的变化:

dispatch_async(_checkQueue, ^{
    for (NSURL *contURL in tempBundleURLs) {
        NSInteger lastSize = 0;
        NSDictionary *fileAttrs = [[NSFileManager defaultManager] attributesOfItemAtPath:[contURL path] error:nil];
        NSInteger fileSize = [[fileAttrs objectForKey:NSFileSize] intValue];

        do {
            lastSize = fileSize;
            [NSThread sleepForTimeInterval:1];

            fileAttrs = [[NSFileManager defaultManager] attributesOfItemAtPath:[contURL path] error:nil];
            fileSize = [[fileAttrs objectForKey:NSFileSize] intValue];

            NSLog(@"doing job");
        } while (lastSize != fileSize);

        NSLog(@"next job");
    }
);

还有其他解决方案吗?

上述解决方案适用于 bin 文件,但不适用于 .bundle(因为 .bundle 文件实际上是目录)。为了使其与 .bundle 一起使用,您应该迭代 .bundle 中的每个文件

【问题讨论】:

    标签: objective-c ios filesystems


    【解决方案1】:

    您可以使用 GCD 的调度源机制 - 使用它您可以观察特定的系统事件(在您的情况下,这是 vnode 类型的事件,因为您正在使用文件系统)。 为了设置特定目录的观察者,我使用了这样的代码:

    - (dispatch_source_t) fileSystemDispatchSourceAtPath:(NSString*) path
    {
        int fileDescr = open([path fileSystemRepresentation], O_EVTONLY);// observe file system events for particular path - you can pass here Documents directory path
        //observer queue is my private dispatch_queue_t object
        dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fileDescr, DISPATCH_VNODE_ATTRIB| DISPATCH_VNODE_WRITE|DISPATCH_VNODE_LINK|DISPATCH_VNODE_EXTEND, observerQueue);// create dispatch_source object to observe vnode events
        dispatch_source_set_registration_handler(source, ^{
            NSLog(@"registered for observation");
            //event handler is called each time file system event of selected type (DISPATCH_VNODE_*) has occurred
            dispatch_source_set_event_handler(source, ^{
    
                dispatch_source_vnode_flags_t flags = dispatch_source_get_data(source);//obtain flags
                NSLog(@"%lu",flags);
    
                if(flags & DISPATCH_VNODE_WRITE)//flag is set to DISPATCH_VNODE_WRITE every time data is appended to file
                {
                    NSLog(@"DISPATCH_VNODE_WRITE");
                    NSDictionary* dict = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
                    float size = [[dict valueForKey:NSFileSize] floatValue];
                    NSLog(@"%f",size);
                }
                if(flags & DISPATCH_VNODE_ATTRIB)//this flag is passed when file is completely written.
                {
                    NSLog(@"DISPATCH_VNODE_ATTRIB");
                    dispatch_source_cancel(source);
                }
                if(flags & DISPATCH_VNODE_LINK)
                {
                    NSLog(@"DISPATCH_VNODE_LINK");
                }
                if(flags & DISPATCH_VNODE_EXTEND)
                {
                    NSLog(@"DISPATCH_VNODE_EXTEND");
                }
                NSLog(@"file = %@",path);
                NSLog(@"\n\n");
            });
    
            dispatch_source_set_cancel_handler(source, ^{
                close(fileDescr);
            });
        });
    
        //we have to resume dispatch_objects
        dispatch_resume(source);
    
        return source;
    }
    

    【讨论】:

    • 文件传输开始时我只收到一次DISPATCH_VNODE_WRITE,传输完成后没有DISPATCH_VNODE_ATTRIB。任何想法为什么?
    【解决方案2】:

    我发现了两种相当可靠(即不是 100% 可靠但足够可靠以满足我的需要)的方法,它们只能与轮询目录的内容结合使用:

    1. 检查NSURLContentModificationDateKey。在传输文件时,此值设置为当前日期。传输完成后,它被设置为原始文件的值:BOOL busy = (-1.0 * [modDate timeintervalSinceNow]) < pollInterval;
    2. 检查NSURLThumbnailDictionaryKey。在传输文件时,此值为nil,之后它包含一个缩略图,但可能仅适用于系统可以从中生成缩略图的文件类型。对我来说不是问题,因为我只关心图像和视频,但也许对你来说。虽然这比解决方案 1 更可靠,但它会严重影响 CPU,如果您在导入目录中有大量文件,甚至可能导致您的应用程序被杀死。

    调度源和轮询可以结合使用,即当调度源检测到变化时,开始轮询,直到没有剩下的繁忙文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多