iOS开发-实现大文件下载与断点下载思路
程序员文章站
2023-12-21 13:53:46
大文件下载
方案一:利用nsurlconnection和它的代理方法,及nsfilehandle(ios9后不建议使用)
相关变量:
@prop...
大文件下载
方案一:利用nsurlconnection和它的代理方法,及nsfilehandle(ios9后不建议使用)
相关变量:
@property (nonatomic,strong) nsfilehandle *writehandle; @property (nonatomic,assign) long long totallength;
1>发送请求
// 创建一个请求 nsurl *url = [nsurl urlwithstring:@""]; nsurlrequest *request = [nsurlrequest requestwithurl:url]; // 使用nsurlconnection发起一个异步请求 [nsurlconnection connectionwithrequest:request delegate:self];
2>在代理方法中处理服务器返回的数据
/** 在接收到服务器的响应时调用下面这个代理方法 1.创建一个空文件 2.用一个句柄对象关联这个空文件,目的是方便在空文件后面写入数据 */ - (void)connection:(nsurlconnection *)connection didreceiveresponse:(nonnull nsurlresponse *)response { // 创建文件路径 nsstring *caches = [nssearchpathfordirectoriesindomains(nscachesdirectory, nsuserdomainmask, yes)lastobject]; nsstring *filepath = [caches stringbyappendingpathcomponent:@"videos.zip"]; // 创建一个空的文件到沙盒中 nsfilemanager *mgr = [nsfilemanager defaultmanager]; [mgr createfileatpath:filepath contents:nil attributes:nil]; // 创建一个用来写数据的文件句柄 self.writehandle = [nsfilehandle filehandleforwritingatpath:filepath]; // 获得文件的总大小 self.totallength = response.expectedcontentlength; } /** 在接收到服务器返回的文件数据时调用下面这个代理方法 利用句柄对象往文件的最后面追加数据 */ - (void)connection:(nsurlconnection *)connection didreceivedata:(nonnull nsdata *)data { // 移动到文件的最后面 [self.writehandle seektoendoffile]; // 将数据写入沙盒 [self.writehandle writedata:data]; } /** 在所有数据接收完毕时,关闭句柄对象 */ - (void)connectiondidfinishloading:(nsurlconnection *)connection { // 关闭文件并清空 [self.writehandle closefile]; self.writehandle = nil; }
方案二:使用nsurlsession的nsurlsessiondownloadtask和nsfilemanager
nsurlsession *session = [nsurlsession sharedsession]; nsurl *url = [nsurl urlwithstring:@""]; // 可以用来下载大文件,数据将会存在沙盒里的tmp文件夹 nsurlsessiondownloadtask *task = [session downloadtaskwithurl:url completionhandler:^(nsurl * _nullable location, nsurlresponse * _nullable response, nserror * _nullable error) { // location :临时文件存放的路径(下载好的文件) // 创建存储文件路径 nsstring *caches = [nssearchpathfordirectoriesindomains(nscachesdirectory, nsuserdomainmask, yes)lastobject]; // response.suggestedfilename:建议使用的文件名,一般跟服务器端的文件名一致 nsstring *file = [caches stringbyappendingpathcomponent:response.suggestedfilename]; /**将临时文件剪切或者复制到caches文件夹 atpath :剪切前的文件路径 topath :剪切后的文件路径 */ nsfilemanager *mgr = [nsfilemanager defaultmanager]; [mgr moveitematpath:location.path topath:file error:nil]; }]; [task resume];
方案三:使用nsurlsessiondownloaddelegate的代理方法和nsfilemanger
- (void)touchesbegan:(nsset<uitouch *> *)touches withevent:(uievent *)event { // 创建一个下载任务并设置代理 nsurlsessionconfiguration *cfg = [nsurlsessionconfiguration defaultsessionconfiguration]; nsurlsession *session = [nsurlsession sessionwithconfiguration:cfg delegate:self delegatequeue:[nsoperationqueue mainqueue]]; nsurl *url = [nsurl urlwithstring:@""]; nsurlsessiondownloadtask *task = [session downloadtaskwithurl:url]; [task resume]; } #pragma mark - /** 下载完毕后调用 参数:lication 临时文件的路径(下载好的文件) */ - (void)urlsession:(nsurlsession *)session downloadtask:(nsurlsessiondownloadtask *)downloadtask didfinishdownloadingtourl:(nsurl *)location{ // 创建存储文件路径 nsstring *caches = [nssearchpathfordirectoriesindomains(nscachesdirectory, nsuserdomainmask, yes)lastobject]; // response.suggestedfilename:建议使用的文件名,一般跟服务器端的文件名一致 nsstring *file = [caches stringbyappendingpathcomponent:downloadtask.response.suggestedfilename]; /**将临时文件剪切或者复制到caches文件夹 atpath :剪切前的文件路径 topath :剪切后的文件路径 */ nsfilemanager *mgr = [nsfilemanager defaultmanager]; [mgr moveitematpath:location.path topath:file error:nil]; } /** 每当下载完一部分时就会调用(可能会被调用多次) 参数: byteswritten 这次调用下载了多少 totalbyteswritten 累计写了多少长度到沙盒中了 totalbytesexpectedtowrite 文件总大小 */ - (void)urlsession:(nsurlsession *)session downloadtask:(nsurlsessiondownloadtask *)downloadtask didwritedata:(int64_t)byteswritten totalbyteswritten:(int64_t)totalbyteswritten totalbytesexpectedtowrite:(int64_t)totalbytesexpectedtowrite{ // 这里可以做些显示进度等操作 } /** 恢复下载时使用 */ - (void)urlsession:(nsurlsession *)session downloadtask:(nsurlsessiondownloadtask *)downloadtask didresumeatoffset:(int64_t)fileoffset expectedtotalbytes:(int64_t)expectedtotalbytes { // 用于断点续传 }
断点下载
方案一:
1>在方案一的基础上新增两个变量和按扭
@property (nonatomic,assign) long long currentlength; @property (nonatomic,strong) nsurlconnection *conn;
2>在接收到服务器返回数据的代理方法中添加如下代码
// 记录断点,累计文件长度 self.currentlength += data.length;
3>点击按钮开始(继续)或暂停下载
- (ibaction)download:(uibutton *)sender { sender.selected = !sender.isselected; if (sender.selected) { // 继续(开始)下载 nsurl *url = [nsurl urlwithstring:@""]; // ****关键点是使用nsmutableurlrequest,设置请求头range nsmutableurlrequest *mrequest = [nsmutableurlrequest requestwithurl:url]; nsstring *range = [nsstring stringwithformat:@"bytes=%lld-",self.currentlength]; [mrequest setvalue:range forhttpheaderfield:@"range"]; // 下载 self.conn = [nsurlconnection connectionwithrequest:mrequest delegate:self]; }else{ [self.conn cancel]; 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 = [nsurlsessionconfiguration defaultsessionconfiguration]; self.session = [nsurlsession sessionwithconfiguration:cfg delegate:self delegatequeue:[nsoperationqueue mainqueue]]; } return _session; } - (ibaction)download:(uibutton *)sender { sender.selected = !sender.isselected; if (self.task == nil) { // 开始(继续)下载 if (self.resumedata) { // 原先有数据则恢复 [self resume]; }else{ [self start]; // 原先没有数据则开始 } }else{ // 暂停 [self pause]; } } // 从零开始 - (void)start{ nsurl *url = [nsurl urlwithstring:@""]; self.task = [self.session downloadtaskwithurl:url]; [self.task resume]; } // 暂停 - (void)pause{ __weak typeof(self) vc = self; [self.task cancelbyproducingresumedata:^(nsdata * _nullable resumedata) { //resumedata : 包含了继续下载的开始位置和下载的url vc.resumedata = resumedata; vc.task = nil; }]; } // 恢复 - (void)resume{ // 传入上次暂停下载返回的数据,就可以回复下载 self.task = [self.session downloadtaskwithresumedata:self.resumedata]; // 开始任务 [self.task resume]; // 清空 self.resumedata = nil; } #pragma mark - nsurlsessiondownloaddelegate /** 下载完毕后调用 参数:lication 临时文件的路径(下载好的文件) */ - (void)urlsession:(nsurlsession *)session downloadtask:(nsurlsessiondownloadtask *)downloadtask didfinishdownloadingtourl:(nsurl *)location{ // 创建存储文件路径 nsstring *caches = [nssearchpathfordirectoriesindomains(nscachesdirectory, nsuserdomainmask, yes)lastobject]; // response.suggestedfilename:建议使用的文件名,一般跟服务器端的文件名一致 nsstring *file = [caches stringbyappendingpathcomponent:downloadtask.response.suggestedfilename]; /**将临时文件剪切或者复制到caches文件夹 atpath :剪切前的文件路径 topath :剪切后的文件路径 */ nsfilemanager *mgr = [nsfilemanager defaultmanager]; [mgr moveitematpath:location.path topath:file error:nil]; } /** 每当下载完一部分时就会调用(可能会被调用多次) 参数: byteswritten 这次调用下载了多少 totalbyteswritten 累计写了多少长度到沙盒中了 totalbytesexpectedtowrite 文件总大小 */ - (void)urlsession:(nsurlsession *)session downloadtask:(nsurlsessiondownloadtask *)downloadtask didwritedata:(int64_t)byteswritten totalbyteswritten:(int64_t)totalbyteswritten totalbytesexpectedtowrite:(int64_t)totalbytesexpectedtowrite{ // 这里可以做些显示进度等操作 } /** 恢复下载时使用 */ - (void)urlsession:(nsurlsession *)session downloadtask:(nsurlsessiondownloadtask *)downloadtask didresumeatoffset:(int64_t)fileoffset expectedtotalbytes:(int64_t)expectedtotalbytes { }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。