zoukankan      html  css  js  c++  java
  • ios大文件存储

    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):

    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

    使用NSOutputStream来实现大文件的存储操作

    Replace the in-memory NSData *data with an NSOutputStream *stream. In -start create 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.

  • 相关阅读:
    读书笔记 effective c++ Item 53 关注编译器发出的警告
    读书笔记 effective c++ Item 52 如果你实现了placement new,你也要实现placement delete
    读书笔记 effective c++ Item 51 实现new和delete的时候要遵守约定
    读书笔记 effective c++ Item 50 了解何时替换new和delete 是有意义的
    读书笔记 effective c++ Item 49 理解new-handler的行为
    读书笔记 effective c++ Item 48 了解模板元编程
    读书笔记 effective c++ Item 47 使用traits class表示类型信息
    读书笔记 effective c++ Item 46 如果想进行类型转换,在模板内部定义非成员函数
    读书笔记 effective c++ Item 45 使用成员函数模板来接受“所有兼容类型”
    读书笔记 effective c++ Item 44 将与模板参数无关的代码抽离出来
  • 原文地址:https://www.cnblogs.com/lisa090818/p/3190616.html
Copyright © 2011-2022 走看看