iOS开发-实现大文件下载与断点下载思路
大文件下载
方案一:利用NSURLConnection和它的代理方法,及NSFileHandle(iOS9后不建议使用)
相关变量:
@property(nonatomic,strong)NSFileHandle*writeHandle; @property(nonatomic,assign)longlongtotalLength;
1>发送请求
//创建一个请求 NSURL*url=[NSURLURLWithString:@""]; NSURLRequest*request=[NSURLRequestrequestWithURL:url]; //使用NSURLConnection发起一个异步请求 [NSURLConnectionconnectionWithRequest:requestdelegate:self];
2>在代理方法中处理服务器返回的数据
/**在接收到服务器的响应时调用下面这个代理方法 1.创建一个空文件 2.用一个句柄对象关联这个空文件,目的是方便在空文件后面写入数据 */ -(void)connection:(NSURLConnection*)connectiondidReceiveResponse:(nonnullNSURLResponse*)response { //创建文件路径 NSString*caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject]; NSString*filePath=[cachesstringByAppendingPathComponent:@"videos.zip"]; //创建一个空的文件到沙盒中 NSFileManager*mgr=[NSFileManagerdefaultManager]; [mgrcreateFileAtPath:filePathcontents:nilattributes:nil]; //创建一个用来写数据的文件句柄 self.writeHandle=[NSFileHandlefileHandleForWritingAtPath:filePath]; //获得文件的总大小 self.totalLength=response.expectedContentLength; } /**在接收到服务器返回的文件数据时调用下面这个代理方法 利用句柄对象往文件的最后面追加数据 */ -(void)connection:(NSURLConnection*)connectiondidReceiveData:(nonnullNSData*)data { //移动到文件的最后面 [self.writeHandleseekToEndOfFile]; //将数据写入沙盒 [self.writeHandlewriteData:data]; } /** 在所有数据接收完毕时,关闭句柄对象 */ -(void)connectionDidFinishLoading:(NSURLConnection*)connection { //关闭文件并清空 [self.writeHandlecloseFile]; self.writeHandle=nil; }
方案二:使用NSURLSession的NSURLSessionDownloadTask和NSFileManager
NSURLSession*session=[NSURLSessionsharedSession]; NSURL*url=[NSURLURLWithString:@""]; //可以用来下载大文件,数据将会存在沙盒里的tmp文件夹 NSURLSessionDownloadTask*task=[sessiondownloadTaskWithURL:urlcompletionHandler:^(NSURL*_Nullablelocation,NSURLResponse*_Nullableresponse,NSError*_Nullableerror){ //location:临时文件存放的路径(下载好的文件) //创建存储文件路径 NSString*caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject]; //response.suggestedFilename:建议使用的文件名,一般跟服务器端的文件名一致 NSString*file=[cachesstringByAppendingPathComponent:response.suggestedFilename]; /**将临时文件剪切或者复制到Caches文件夹 AtPath:剪切前的文件路径 toPath:剪切后的文件路径 */ NSFileManager*mgr=[NSFileManagerdefaultManager]; [mgrmoveItemAtPath:location.pathtoPath:fileerror:nil]; }]; [taskresume];
方案三:使用NSURLSessionDownloadDelegate的代理方法和NSFileManger
-(void)touchesBegan:(NSSet<UITouch*>*)toucheswithEvent:(UIEvent*)event { //创建一个下载任务并设置代理 NSURLSessionConfiguration*cfg=[NSURLSessionConfigurationdefaultSessionConfiguration]; NSURLSession*session=[NSURLSessionsessionWithConfiguration:cfgdelegate:selfdelegateQueue:[NSOperationQueuemainQueue]]; NSURL*url=[NSURLURLWithString:@""]; NSURLSessionDownloadTask*task=[sessiondownloadTaskWithURL:url]; [taskresume]; } #pragmamark- /** 下载完毕后调用 参数:lication临时文件的路径(下载好的文件) */ -(void)URLSession:(NSURLSession*)sessiondownloadTask:(NSURLSessionDownloadTask*)downloadTask didFinishDownloadingToURL:(NSURL*)location{ //创建存储文件路径 NSString*caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject]; //response.suggestedFilename:建议使用的文件名,一般跟服务器端的文件名一致 NSString*file=[cachesstringByAppendingPathComponent:downloadTask.response.suggestedFilename]; /**将临时文件剪切或者复制到Caches文件夹 AtPath:剪切前的文件路径 toPath:剪切后的文件路径 */ NSFileManager*mgr=[NSFileManagerdefaultManager]; [mgrmoveItemAtPath:location.pathtoPath:fileerror:nil]; } /** 每当下载完一部分时就会调用(可能会被调用多次) 参数: bytesWritten这次调用下载了多少 totalBytesWritten累计写了多少长度到沙盒中了 totalBytesExpectedToWrite文件总大小 */ -(void)URLSession:(NSURLSession*)sessiondownloadTask:(NSURLSessionDownloadTask*)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{ //这里可以做些显示进度等操作 } /** 恢复下载时使用 */ -(void)URLSession:(NSURLSession*)sessiondownloadTask:(NSURLSessionDownloadTask*)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes { //用于断点续传 }
断点下载
方案一:
1>在方案一的基础上新增两个变量和按扭
@property(nonatomic,assign)longlongcurrentLength; @property(nonatomic,strong)NSURLConnection*conn;
2>在接收到服务器返回数据的代理方法中添加如下代码
//记录断点,累计文件长度 self.currentLength+=data.length;
3>点击按钮开始(继续)或暂停下载
-(IBAction)download:(UIButton*)sender{ sender.selected=!sender.isSelected; if(sender.selected){//继续(开始)下载 NSURL*url=[NSURLURLWithString:@""]; //****关键点是使用NSMutableURLRequest,设置请求头Range NSMutableURLRequest*mRequest=[NSMutableURLRequestrequestWithURL:url]; NSString*range=[NSStringstringWithFormat:@"bytes=%lld-",self.currentLength]; [mRequestsetValue:rangeforHTTPHeaderField:@"Range"]; //下载 self.conn=[NSURLConnectionconnectionWithRequest:mRequestdelegate:self]; }else{ [self.conncancel]; self.conn=nil; } }
4>在接受到服务器响应执行的代理方法中第一行添加下面代码,防止重复创建空文件
if(self.currentLength)return;
方案二:使用NSURLSessionDownloadDelegate的代理方法
所需变量
@property(nonatomic,strong)NSURLSession*session; @property(nonatomic,strong)NSData*resumeData;//包含了继续下载的开始位置和下载的url @property(nonatomic,strong)NSURLSessionDownloadTask*task;
方法
//懒加载session -(NSURLSession*)session { if(!_session){ NSURLSessionConfiguration*cfg=[NSURLSessionConfigurationdefaultSessionConfiguration]; self.session=[NSURLSessionsessionWithConfiguration:cfgdelegate:selfdelegateQueue:[NSOperationQueuemainQueue]]; } return_session; } -(IBAction)download:(UIButton*)sender{ sender.selected=!sender.isSelected; if(self.task==nil){//开始(继续)下载 if(self.resumeData){//原先有数据则恢复 [selfresume]; }else{ [selfstart];//原先没有数据则开始 } }else{//暂停 [selfpause]; } } //从零开始 -(void)start{ NSURL*url=[NSURLURLWithString:@""]; self.task=[self.sessiondownloadTaskWithURL:url]; [self.taskresume]; } //暂停 -(void)pause{ __weaktypeof(self)vc=self; [self.taskcancelByProducingResumeData:^(NSData*_NullableresumeData){ //resumeData:包含了继续下载的开始位置和下载的url vc.resumeData=resumeData; vc.task=nil; }]; } //恢复 -(void)resume{ //传入上次暂停下载返回的数据,就可以回复下载 self.task=[self.sessiondownloadTaskWithResumeData:self.resumeData]; //开始任务 [self.taskresume]; //清空 self.resumeData=nil; } #pragmamark-NSURLSessionDownloadDelegate /** 下载完毕后调用 参数:lication临时文件的路径(下载好的文件) */ -(void)URLSession:(NSURLSession*)sessiondownloadTask:(NSURLSessionDownloadTask*)downloadTask didFinishDownloadingToURL:(NSURL*)location{ //创建存储文件路径 NSString*caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject]; //response.suggestedFilename:建议使用的文件名,一般跟服务器端的文件名一致 NSString*file=[cachesstringByAppendingPathComponent:downloadTask.response.suggestedFilename]; /**将临时文件剪切或者复制到Caches文件夹 AtPath:剪切前的文件路径 toPath:剪切后的文件路径 */ NSFileManager*mgr=[NSFileManagerdefaultManager]; [mgrmoveItemAtPath:location.pathtoPath:fileerror:nil]; } /** 每当下载完一部分时就会调用(可能会被调用多次) 参数: bytesWritten这次调用下载了多少 totalBytesWritten累计写了多少长度到沙盒中了 totalBytesExpectedToWrite文件总大小 */ -(void)URLSession:(NSURLSession*)sessiondownloadTask:(NSURLSessionDownloadTask*)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{ //这里可以做些显示进度等操作 } /** 恢复下载时使用 */ -(void)URLSession:(NSURLSession*)sessiondownloadTask:(NSURLSessionDownloadTask*)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes { }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。