Hello, My NSDocument based app uses packages with the following structure:
- document.package +- metadata.plist (small, mutable) +- large0.file (large, immutable) +- large1.file (large, immutable) +- large2.file (large, immutable) While the metadata.plist file can change any time, all large files are created once and then stay as they are. As my "large0-2" files can be several gigabytes, I try to carefully avoid unnecessary IO by using document packages with NSFileWrapper. My package reading/writing methods resemble the ones in the "Document Package with iCloud" sample (But I don't use iCloud): http://developer.apple.com/library/mac/#samplecode/PackagedDocument/ I appended the relevant parts of my code at the end of this message. With this setup, I was hoping that the occasions where the document architecture has to copy the whole bundle are reduced to: - File duplication - Moves to another volume But after investigating file activity with Instruments.app, it turned out that my app is reading and writing chunks of my unmodified, immutable & large files during each save. It seems that the copying is related to document revisions (a.k.a. Versions). Instruments logs hundreds of IO operations in the form of: # Caller Function FD Path Bytes ... 70 copyfile read 22 document.package/large0.file 1048576 71 copyfile write 23 /.vol/16777218/2/.DocumentRevisions-V100/staging/adding.Wohcjo4i/4772FAAA-78D3-44A9-9412-A2D651B6EB5A.package/large0.file 1048576 70 copyfile read 22 document.package/large0.file 1048576 71 copyfile write 23 /.vol/16777218/2/.DocumentRevisions-V100/staging/adding.Wohcjo4i/4772FAAA-78D3-44A9-9412-A2D651B6EB5A.package/large0.file 1048576 70 copyfile read 22 document.package/large0.file 1048576 71 copyfile write 23 /.vol/16777218/2/.DocumentRevisions-V100/staging/adding.Wohcjo4i/4772FAAA-78D3-44A9-9412-A2D651B6EB5A.package/large0.file 1048576 ... How can I tell Versions that the only file that constantly changes within my document.package is metadata.info? (Without turning off document revisions altogether) I am targetting 10.8 (with sandboxing enabled) and also adopted async saving and autosavesInPlace. with kind regards, Thomas --- - (NSFileWrapper*)fileWrapperOfType:(NSString*)typeName error:(NSError**)outError { if([self documentFileWrapper] == nil) { NSFileWrapper* documentFileWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil]; [self setDocumentFileWrapper:documentFileWrapper]; [documentFileWrapper release]; } NSURL* documentURL = [self fileURL] == nil ? [self autosavedContentsFileURL] : [self fileURL]; if(documentURL) { //Check if we already have a metadata file wrapper. If "YES" remove it. NSFileWrapper* previousRecordingInfoFileWrapper = [[[self documentFileWrapper] fileWrappers] objectForKey:kSSWInfoPlistFilename]; if(previousRecordingInfoFileWrapper != nil) { [[self documentFileWrapper] removeFileWrapper:previousRecordingInfoFileWrapper]; } NSData* recordingInfoData = [NSPropertyListSerialization dataFromPropertyList:recordingInfoDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&serializationErrorDescriptions]; [self unblockUserInteraction]; NSFileWrapper* recordingInfoFileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:recordingInfoData]; [recordingInfoFileWrapper setPreferredFilename:kSSWInfoPlistFilename]; [[self documentFileWrapper] addFileWrapper:recordingInfoFileWrapper]; [recordingInfoFileWrapper release]; if(([[[self documentFileWrapper] fileWrappers] objectForKey:kSSWRecordingFrameName] == nil)) { NSFileWrapper* frameFileWrapper = [[NSFileWrapper alloc] initWithURL:[documentURL URLByAppendingPathComponent:kSSWRecordingFrameName] options:0 error:outError]; [frameFileWrapper setPreferredFilename:kSSWRecordingFrameName]; [[self documentFileWrapper] addFileWrapper:frameFileWrapper]; [frameFileWrapper release]; } ... } } - (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError **)outError { BOOL didRead = NO; NSFileWrapper* recordingInfoWrapper = [[fileWrapper fileWrappers] objectForKey:kSSWInfoPlistFilename]; if(!recordingInfoWrapper) { NSMutableDictionary* errorDetail = [NSMutableDictionary dictionary]; NSString* errorDescription = NSLocalizedString(@"Could not open recording.\nThe recording is missing it's metadata file.", @"Displayed when trying to open a corrupted bundle"); [errorDetail setValue:errorDescription forKey:NSLocalizedDescriptionKey]; if(outError) { *outError = [NSError errorWithDomain:kSSWRecordingErrorDomain code:100 userInfo:errorDetail]; } } else { NSDictionary* recordingInfoDict = [NSPropertyListSerialization propertyListWithData:[recordingInfoWrapper regularFileContents] options:0 format:nil error:outError]; if(recordingInfoDict) { self.recordingInfo = recordingInfoDict; } } [self setDocumentFileWrapper:fileWrapper]; return didRead; } _______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com