ITunes File Sharing app: real-time monitoring for incoming data

I am working on an iOS project that supports iTunes file sharing . Real-time goal to track incoming / modified data.

I am using (modified) the DirectoryWatcher class from the sample Apple code and also tried this source code .

NSBundle data (* .bundle), and some packages are in the ranges of 100-500 MB, depends on its contents, some video / audio materials. The packages have an xml-based descriptor file.

The problem is that any of these codes above notifies you of a fire or something else when the data has just begun to be copied, and not when the copy / modify / delete process is completely completed .

Tried the following:

checking file attributes:

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

looking for fileSize changes:

 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"); } ); 

any other solutions?

The solution above works fine for bin files, but not for .bundle (since .bundle files are actually directories). To make it work with .bundle, you have to iterate over every file inside .bundle

+4
source share
2 answers

You can use the GCD sending source mechanism - using it, you can observe certain system events (in your case, these are events of the vnode type, since you are working with the file system). To configure the observer for a specific directory, I used this code:

 - (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_ATTRIB | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_LINK | DISPATCH_VNODE_EXTEND, observerQueue); // create dispatch_source object to observe vnode events - (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; } 
+8
source

I found two fairly reliable (i.e. not 100% reliable, but reliable enough for my needs) approaches that work only in conjunction with polling the contents of a directory:

  • Check NSURLContentModificationDateKey . While the file is being transferred, this value is set to the current date. Upon completion of the transfer, the value that the original file had was set: BOOL busy = (-1.0 * [modDate timeintervalSinceNow]) < pollInterval;
  • Check NSURLThumbnailDictionaryKey . While the file is being transferred, this value is nil , after which it copies the thumbnail, but probably only for the types of files from which the system can create thumbnails. Not a problem for me, because I only care about images and videos, but maybe for you. Although it is more reliable than solution 1, it is very clogging the processor and may even cause your application to be killed if there are many files in the import directory.

Sending sources and polling can be combined, that is, when the sending source detects a change, start polling until the downloaded files remain.

0
source

Source: https://habr.com/ru/post/1401731/


All Articles