###使用xcode自带的代理方法。xcode
代理方法: //这个是开始下载时 调用的方法。 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response //这个也是每次都在调用的方法。 data(表明每次下载的数据大小) - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data //这个方法是在下载时一直会调用的。这里有三个参数。 bytesWritten(表明本次下载下载了多少) totalBytesWritten(表明已经下载了多少) totalBytesExpectedToWrite(表明文件总大小是多少) - (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten: (NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite; //这个方法在下载完成后 会自动调用。 connection(这个参数是下完完成后 文件的路径) - (void)connectionDidFinishLoading:(NSURLConnection *)connection;
1)内存不会暴涨 可是找不到下载完毕以后的文件。 2)能够直接显示下载进度。服务器
直接设置NSMutableData属性来接受下载完毕的数据 . 1)内存依然“暴涨”:至关于仍是先将整个文件下载到内存中 而后在写入沙盒中 2) 没法直接显示下载进度。须要手动计算。session
//用已下载的本地路径去建立handle NSFileHandle * handle = [NSFileHandle fileHandleForWritingAtPath:@"/Users/ym/Desktop/haha.zip"]; //若是handle建立成功 表明本地路径有文件。 if (handle) { 操做句柄到最后 [handle seekToEndOfFile]; // 拼接文件/写入文件 [handle writeData:data]; // 关闭句柄 [handle closeFile]; }else{ //本地路径没有文件。 就从新建立一个本地文件路径 [data writeToFile:@"/Users/ym/Desktop/haha.zip" atomically:YES]; }
问题:屡次下载,会直接在以前的文件后拼接文件—>得不到正确的文件数据。app
//首先要根据文件路径来建立stream 。若是你的这个路径没有文件。他会自动给你建立一个文件。atom
NSOutputStream * stream = [NSOutputStream outputStreamToFileAtPath:@" /Users/ym/Desktop/haha.zip" append:YES]; //建立一个属性。来存储文件和关闭stream self.stream = stream; //开启任务。 [self.stream open]; //在方法里 来拼接data内容。 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ [self.stream write:data.bytes maxLength:data.length]; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection{ //在下载结束任务后,关闭stream任务。 [self.stream close]; }
这样的下载任务。仍是会有和handle同样的问题。屡次下载和暂停下载以后继续下载。拼接的文件都是错误的。url
因此这里就引入了断点续传功能。代理
###用HEAD请求来获取下载文件的总大小code
//文件路径 NSString *urlString = @"http://127.0.0.1/music.zip"; NSURL *url = [NSURL URLWithString:urlString]; //建立请求 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 设置请求方法: request.HTTPMethod = @"HEAD"; // 发送 HEAD 请求. // HEAD 请求使用什么方法发送? ---- 通常使用同步方式发送HEAD请求. NSURLResponse *response = nil; [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL]; //打印出来的就是你的所须要的文件总大小。 NSLog(@"response:%zd",response.expectedContentLength);
//这里返回值是一个字典。 [[NSFileManager defaultManager] attributesOfItemAtPath:self.filePath error:NULL];
//这个就是打印字典的信息。 咱们所须要的就是NSFileSize ** NSFileCreationDate = "2016-05-05 12:59:14 +0000"; ** NSFileExtensionHidden = 0; ** NSFileGroupOwnerAccountID = 20; ** NSFileGroupOwnerAccountName = staff; ** NSFileModificationDate = "2016-05-05 12:59:17 +0000"; ** NSFileOwnerAccountID = 501; ** NSFilePosixPermissions = 420; ** NSFileReferenceCount = 1; ** NSFileSize = 573278888; ** NSFileSystemFileNumber = 19578034; ** NSFileSystemNumber = 16777217; ** NSFileType = NSFileTypeRegular;
因此要接收这个字典 同时返回NSFileSize.获取本地文件已经下载的大小。 知道了已经下载的大小,还有总大小。咱们就能够根据这两个数值来进行断点续传了。orm
设置请求头信息。 <1>格式: Range格式: bytes = x-y 从x位置开始下载,下载y个字节。 bytes = x- 从x开始 下载到完毕。 bytes = -x 从开始下载x个字节。 <2>特色: 一旦Range 属性设置成功,相应的状态码就是206ip
//startSize 就是上文提到的dict中的NSFileSize。要把这个oc属性转化为字符串。 //bytes=zd - 就是从你断点的位置下载到文件结束
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",startSize]; [request setValue:range forHTTPHeaderField:@"Range"];
利用代理NSURLSessionDownloadDelegate 1.主要利用的代理方法。
这个是每次下载都调用的方法。和上边的同样。
-(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 didFinishDownloadingToURL:(NSURL *)location
-(NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
NSString * urlString = @"http://127.0.0.1/music.zip"; NSURL * url = [NSURL URLWithString:urlString];
NSURLSession * session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
NSURLSessionDownloadTask * task = [session downloadTaskWithURL:url]; self.oldSession = session; self.task = task; [task resume];
[self.task cancelByProducingResumeData:^(NSData * _Nullable resumeData) { self.resumeData = resumeData; }]; self.task = nil;
if (self.resumeData) { self.task = [self.oldSession downloadTaskWithResumeData:self.resumeData]; [self.task resume]; }