iTunes文件共享应用程序:实时监控传入数据

时间:2012-03-16 03:39:54

标签: objective-c ios filesystems

我正在研究支持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

中的每个文件

2 个答案:

答案 0 :(得分:8)

您可以使用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;
}

答案 1 :(得分:1)

我发现两个相当可靠(即不是100%可靠但足以满足我的需求)的方法,这些方法只与轮询目录的内容一起使用:

  1. 检查NSURLContentModificationDateKey。在传输文件时,此值设置为当前日期。传输完成后,将其设置为原始文件的值:BOOL busy = (-1.0 * [modDate timeintervalSinceNow]) < pollInterval;
  2. 检查NSURLThumbnailDictionaryKey。在传输文件时,此值为nil,之后它会包含缩略图,但可能仅适用于系统可以生成缩略图的文件类型。对我来说不是问题,因为我只关心图像和视频,但也许对你而言。虽然这比解决方案1更可靠,但是如果你在导入目录中有很多文件,它会对CPU产生很大的影响,甚至可能导致你的应用程序被杀死。
  3. 可以组合调度源和轮询,即当调度源检测到更改时,开始轮询直到没有剩余繁忙的文件。