ios大文件存储
2013-07-15 09:52
176 查看
I am using Erica Sadun's method of Asynchronous Downloads (link here for the project file: download), however her method does not work with files that have a big size (50 mb or above). If I try to download a file above 50 mb, it will usually crash due to a memory crash. Is there anyway I can tweak this code so that it works with large files as well? Here is the code I have in the DownloadHelper Classes (which is already in the download link):
使用NSOutputStream来实现大文件的存储操作
Replace the in-memory
As data comes in, write it to the stream:
When you're done, close the stream:
A better approach would be to add the stream in addition to the data ivar, set the helper as the stream's delegate, buffer incoming data in the data ivar, then dump the data ivar's contents to the helper whenever the stream sends the helper its space-available event and clear it out of the data ivar.
21 | I am using Erica Sadun's method of Asynchronous Downloads (link here for the project file: download), however her method does not work with files that have a big size (50 mb or above). If I try to download a file above 50 mb, it will usually crash due to a memory crash. Is there anyway I can tweak this code so that it works with large files as well? Here is the code I have in the DownloadHelper Classes (which is already in the download link): .h @protocolDownloadHelperDelegate<NSObject>@optional-(void) didReceiveData:(NSData*) theData;-(void) didReceiveFilename:(NSString*) aName;-(void) dataDownloadFailed:(NSString*) reason;-(void) dataDownloadAtPercent:(NSNumber*) aPercent;@end@interfaceDownloadHelper:NSObject{NSURLResponse*response;NSMutableData*data;NSString*urlString;NSURLConnection*urlconnection; id <DownloadHelperDelegate>delegate; BOOL isDownloading;}@property(retain)NSURLResponse*response;@property(retain)NSURLConnection*urlconnection;@property(retain)NSMutableData*data;@property(retain)NSString*urlString;@property(retain) id delegate;@property(assign) BOOL isDownloading;+(DownloadHelper*) sharedInstance;+(void) download:(NSString*) aURLString;+(void) cancel;@end .m #define DELEGATE_CALLBACK(X, Y)if(sharedInstance.delegate&&[sharedInstance.delegate respondsToSelector:@selector(X)])[sharedInstance.delegate performSelector:@selector(X) withObject:Y];#define NUMBER(X)[NSNumber numberWithFloat:X]staticDownloadHelper*sharedInstance = nil;@implementationDownloadHelper@synthesize response;@synthesize data;@synthesizedelegate;@synthesize urlString;@synthesize urlconnection;@synthesize isDownloading;-(void) start { self.isDownloading = NO; NSURL *url =[NSURL URLWithString:self.urlString];if(!url){NSString*reason =[NSString stringWithFormat:@"Could not create URL from string %@", self.urlString]; DELEGATE_CALLBACK(dataDownloadFailed:, reason);return;}NSMutableURLRequest*theRequest =[NSMutableURLRequest requestWithURL:url];if(!theRequest){NSString*reason =[NSString stringWithFormat:@"Could not create URL request from string %@", self.urlString]; DELEGATE_CALLBACK(dataDownloadFailed:, reason);return;} self.urlconnection =[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];if(!self.urlconnection){NSString*reason =[NSString stringWithFormat:@"URL connection failed for string %@", self.urlString]; DELEGATE_CALLBACK(dataDownloadFailed:, reason);return;} self.isDownloading = YES;// Create the new data object self.data =[NSMutableData data]; self.response = nil;[self.urlconnection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];}-(void) cleanup { self.data = nil; self.response = nil; self.urlconnection = nil; self.urlString = nil; self.isDownloading = NO;}-(void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)aResponse {// store the response information self.response = aResponse;// Check for bad connectionif([aResponse expectedContentLength]<0){NSString*reason =[NSString stringWithFormat:@"Invalid URL [%@]", self.urlString]; DELEGATE_CALLBACK(dataDownloadFailed:, reason);[connection cancel];[self cleanup];return;}if([aResponse suggestedFilename]) DELEGATE_CALLBACK(didReceiveFilename:,[aResponse suggestedFilename]);}-(void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)theData {// append the new data and update the delegate[self.data appendData:theData];if(self.response){float expectedLength =[self.response expectedContentLength];float currentLength = self.data.length;float percent = currentLength / expectedLength; DELEGATE_CALLBACK(dataDownloadAtPercent:, NUMBER(percent));}}-(void)connectionDidFinishLoading:(NSURLConnection*)connection {// finished downloading the data, cleaning up self.response = nil;// Delegate is responsible for releasing dataif(self.delegate){NSData*theData =[self.data retain]; DELEGATE_CALLBACK(didReceiveData:, theData);}[self.urlconnection unscheduleFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];[self cleanup];}-(void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error { self.isDownloading = NO;NSLog(@"Error: Failed connection, %@",[error localizedDescription]); DELEGATE_CALLBACK(dataDownloadFailed:,@"Failed Connection");[self cleanup];}+(DownloadHelper*) sharedInstance {if(!sharedInstance) sharedInstance =[[self alloc] init];return sharedInstance;}+(void) download:(NSString*) aURLString {if(sharedInstance.isDownloading){NSLog(@"Error: Cannot start new download until current download finishes"); DELEGATE_CALLBACK(dataDownloadFailed:,@"");return;} sharedInstance.urlString = aURLString;[sharedInstance start];}+(void) cancel {if(sharedInstance.isDownloading)[sharedInstance.urlconnection cancel];}@end And finally this is how I write the file with the two classes above it: -(void) didReceiveData:(NSData*) theData {if(![theData writeToFile:self.savePath atomically:YES])[self doLog:@"Error writing data to file"];[theData release];} If someone could help me out I would be so glad! Thanks, Kevin |
Replace the in-memory
NSData *datawith an
NSOutputStream *stream. In
-startcreate the stream to append and open it:
stream =[[NSOutputStream alloc] initToFileAtPath:path append:YES];[stream open];
As data comes in, write it to the stream:
NSUInteger left =[theData length];NSUInteger nwr =0;do{ nwr =[stream write:[theData bytes] maxLength:left];if(-1== nwr)break; left -= nwr;}while(left >0);if(left){NSLog(@"stream error: %@",[stream streamError]);}
When you're done, close the stream:
[stream close];
A better approach would be to add the stream in addition to the data ivar, set the helper as the stream's delegate, buffer incoming data in the data ivar, then dump the data ivar's contents to the helper whenever the stream sends the helper its space-available event and clear it out of the data ivar.
相关文章推荐
- IOS文件存储小结
- IOS线程数据篇13之数据存储,文件内容追加
- iOS文件处理,将图片存到手机目录里面 创建文件夹,NSFileManager用来存储图片,然后遍历将图片取出上传到服务器哦!!
- iOS 录视频,相册选择视频,视频压缩,存储本地文件,播放,上传
- iOS 数据存储 plist文件存储
- IOS开发--数据持久化篇之文件存储(二)
- ios 文件存储 iOS Data Storage Guidelines 和 "do not back up"文件属性
- IOS文件存储小结
- iOS沙盒文件存储
- iOS音频文件存储
- [ios2] iOS 5的文件存储策略应对【转】
- ios 字符串,字典,数组存储到本地文件
- iOS应用程序安全(20)-本地数据存储及其安全性(NSUserDefaults, CoreData, Sqlite, Plist 文件)
- iOS iPhone 开发中的文件读写及数据存储
- iOS真机沙盒文件查看 图片批量存储/获取/删除
- IOS数据的存储和读取之文件操作
- 【iOS数据存储】iOS文件系统介绍
- ios沙盒机制及文件存储操作
- iOS文件使用总结(数据持久化存储)
- iOS开发之JSON转PLIST(把存储json格式的文件转换成plist文件)