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
{
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。