iOS开发网络篇 一一 NSURLSessionDataTask实现大文件离线断点下载(重点)
来源:互联网 发布:千方百计医药软件 编辑:程序博客网 时间:2024/06/05 20:23
源码下载: https://github.com/coderZYGui/ZYBreakpointDownload
效果图如下:
知识点:
1.获取指定文件路径对应的文件大小(已经下载过的文件数据大小 )
2.( 断点下载思路 )使用NSMutableURLRequest 创建可变请求. 设置请求头信息,告诉服务器请求的是哪一部分数据(请求当前下载过的数据( 知识点1,中已经下载过的文件数据大小) 后的数据 )
// 只要设置HTTP请求头的Range属性, 就可以实现从指定位置开始下载 表示头500个字节:Range: bytes=0-499 表示第二个500字节:Range: bytes=500-999 表示最后500个字节:Range: bytes=-500 表示500字节以后的范围:Range: bytes=500-3.使用response.expectedContentLength 获得本次请求的文件数据总大小.
注意:
本次请求的文件数据大小 !=文件总大小(第一次发送请求时,response.expectedContentLength 为文件的大小, 如果再次发送请求的时候,此时的self.totalSize就小于文件的大小,因此在后面计算 1.0 * self.currentSize / self.totalSize的时候,会出现数据错乱)因此要加上当前已经下载的数据.
4. 在接收到服务器响应的代理方法中. 默认是取消该请求.设置枚举为NSURLSessionResponseAllow 接收
completionHandler(NSURLSessionResponseAllow);
5.判断下载数据 self.currentSize == 0创建空文件.防止多次发送请求时创建多个空文件,导致文件数据大小紊乱.
6.使用文件句柄在每次下载过的数据后,继续拼接. [ self.handle seekToEndofFile ];
7. 将文件的总数据 和已经下载的文件数据 都保存到沙盒中, 当程序运行时将已经下载的数据 / 文件总数据 设置到 slider的value上.
8. 释放 NSURLSession 对象
- (void)dealloc{ // 如果session设置代理的话,会有一个强引用.不会被释放.因此最后要释放session对象:调用下面两个方法都行.\ 否则会有内存泄漏. // finishTasksAndInvalidate [self.session invalidateAndCancel];}
代码:
// Created by 朝阳 on 2017/12/19.// Copyright © 2017年 sunny. All rights reserved.//#import "ViewController.h"#define FileName @"zy.mp4"@interface ViewController ()<NSURLSessionDataDelegate>@property (nonatomic, strong) NSFileHandle *handle;@property (nonatomic, assign) NSInteger totalSize;@property (nonatomic, assign) NSInteger currentSize;@property (nonatomic, strong) NSString *fullPath;@property (weak, nonatomic) IBOutlet UISlider *slider;@property (nonatomic,strong) NSURLSessionDataTask *dataTask;@property (nonatomic,strong) NSURLSession *session;@end@implementation ViewController- (void)viewDidLoad{ [super viewDidLoad]; //设置slider的进度状态 = 1.0 * 已经下载的文件大小 / 总文件大小 self.slider.value = [self getSandboxFileSize]; if (self.slider.value == 1.0) { self.slider.value = 0; } }- (CGFloat)getSandboxFileSize{ //1. 读取沙盒中保存的总文件大小 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSNumber *totalFileSize = [defaults objectForKey:@"fileSize"]; NSNumber *currentFileSize = [defaults objectForKey:@"currentFileSize"]; NSInteger totalSize = [totalFileSize integerValue]; NSInteger currentSize = [currentFileSize integerValue]; NSLog(@"%ld",totalSize); NSLog(@"%ld",currentSize); return 1.0 * currentSize / totalSize;}#pragma -mark lazy loading- (NSURLSession *)session{ if (!_session) { //创建会话对象,并设置代理 _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; } return _session;}- (NSString *)fullPath{ if (!_fullPath) { //2. 获取文件全路径 _fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingString:FileName]; } return _fullPath;}- (NSURLSessionDataTask *)dataTask{ if (!_dataTask) { //1. url NSURL *url = [NSURL URLWithString:@"http://flv2.bn.netease.com/videolib3/1604/28/fVobI0704/SD/fVobI0704-mobile.mp4"]; //2. 创建请求对象 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 获取指定文件路径对应的文件大小(当前已经下载的文件大小) self.currentSize = [self getFileSize]; NSLog(@"currentSize----+++++++++++++++++++----%ld",self.currentSize); //2.1 设置请求头信息,告诉服务器请求的哪一部分数据(请求当前下载过的数据 之后的数据) // 只要设置HTTP请求头的Range属性, 就可以实现从指定位置开始下载 /* 表示头500个字节:Range: bytes=0-499 表示第二个500字节:Range: bytes=500-999 表示最后500个字节:Range: bytes=-500 表示500字节以后的范围:Range: bytes=500- */ NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize]; [request setValue:range forHTTPHeaderField:@"Range"]; //3. 创建Task任务 _dataTask = [self.session dataTaskWithRequest:request]; } return _dataTask;}// 获取指定文件路径对应的文件大小- (NSInteger)getFileSize{ NSDictionary *fileInfoDict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.fullPath error:nil]; NSLog(@"%@",fileInfoDict); // 获得字典中文件的信息-文件大小 // currentSize = self.currentSize; NSInteger currentSize = [fileInfoDict[@"NSFileSize"] integerValue]; return currentSize;}- (IBAction)startDwonload:(id)sender{ NSLog(@"+++++++++++++++开始下载"); //5. 执行Task [self.dataTask resume];}- (IBAction)supendDownload:(id)sender{ NSLog(@"+++++++++++++++暂停下载"); [self.dataTask suspend];}// cancel方法: 不可恢复下载- (IBAction)cancelDownload:(id)sender{ NSLog(@"+++++++++++++++取消下载"); [self.dataTask cancel]; // 清空dataTask.在resumeDownload:方法中,self.dataTask 走懒加载方法 self.dataTask = nil;}// 恢复下载- (IBAction)resumeDownload:(id)sender{ NSLog(@"+++++++++++++++恢复下载"); [self.dataTask resume];}#pragma -mark NSURLSessionDataDelegate/** 接收到服务器的响应 它默认会取消该请求 @param session 会话对象 @param dataTask 请求任务 @param response 响应头信息 @param completionHandler 回调 传给系统 */- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{ //0. 得到 文件的总大小(本次请求的文件数据的总大小) // 本次请求的文件数据大小 != 文件总大小(如果再次发送请求的时候,此时的self.totalSize 就小于文件的大小,因此在\ 在后面计算 1.0 * self.currentSize / self.totalSize 的时候,会出现数据错乱) 因此要加上当前已经下载的数据. self.totalSize = response.expectedContentLength + self.currentSize; // 将文件总大小写入到沙盒中 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:@(self.totalSize) forKey:@"fileSize"]; /* NSURLSessionResponseCancel = 0,取消 默认 NSURLSessionResponseAllow = 1, 接收 NSURLSessionResponseBecomeDownload = 2, 变成下载任务 NSURLSessionResponseBecomeStream 变成流 */ //1. 因为系统默认是 取消任务请求. 所以要设置 枚举 为接收 completionHandler(NSURLSessionResponseAllow); // 如果当前下载的数据为0. 就创建一个空文件(防止,多创建空文件导致文件大小紊乱) if (self.currentSize == 0) { //3. 创建一个空文件(将文件写入到沙盒中) [[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil]; } //4. 创建文件句柄 self.handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath]; //5. 每次在下载过数据后,继续拼接 [self.handle seekToEndOfFile];}/** 接收到服务器返回的数据 调用多次 @param session 会话对象 @param dataTask 请求任务 @param data 本次下载的数据 */-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{ //1. 写入数据到文件 [self.handle writeData:data]; //2. 拼接已经下载过的数据 self.currentSize += data.length; // 将已经下载的文件大小写入到沙盒中 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:@(self.currentSize) forKey:@"currentFileSize"]; //3. 下载进度 NSLog(@"%f",1.0 * self.currentSize / self.totalSize); self.slider.value = 1.0 * self.currentSize / self.totalSize;}/** 请求结束或失败的时候调用 @param session 会话对象 @param task 请求任务 @param error 错误信息 */- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{ //1. 关闭文件句柄 [self.handle closeFile]; self.handle = nil; NSLog(@"%@",self.fullPath); }- (void)dealloc{ // 如果session设置代理的话,会有一个强引用.不会被释放.因此最后要释放session对象:调用下面两个方法都行.\ 否则会有内存泄漏. // finishTasksAndInvalidate [self.session invalidateAndCancel];}@end
- iOS开发网络篇 一一 NSURLSessionDataTask实现大文件离线断点下载(重点)
- iOS开发网络篇 一一 NSURLConnection-大文件断点下载
- iOS开发网络篇 一一 NSURLSessionDownloadTask实现断点下载
- iOS开发之网络编程--4、NSURLSessionDataTask实现文件下载(离线断点续传下载) <进度值显示优化>
- iOS之网络—— NSURLSessionDataTask文件离线断点下载、NSURLSession文件上传、AFN基本使用、Cocoapods安装
- iOS开发网络篇 一一 NSURLSessionDownloadTask实现文件下载
- ios:NSURLSessionDataTask做文件断点下载
- iOS开发网络篇之文件下载、大文件下载、断点下载
- iOS开发网络篇之文件下载、大文件下载、断点下载
- iOS开发网络篇之文件下载、大文件下载、断点下载
- iOS开发网络篇之文件下载、大文件下载、断点下载
- iOS开发网络篇之文件下载、大文件下载、断点下载
- iOS开发网络篇之文件下载、大文件下载、断点下载
- iOS开发网络篇之文件下载、大文件下载、断点下载
- iOS开发网络篇之文件下载、大文件下载、断点下载
- iOS开发网络篇之文件下载、大文件下载、断点下载
- iOS开发网络篇之文件下载、大文件下载、断点下载
- iOS开发网络篇之文件下载、大文件下载、断点下载
- 数据结构实验之查找三:树的种类统计
- Leetcode 406. Queue Reconstruction by Height[Medium]
- Ashampoo Burning Studio 19(阿香婆光盘刻录软件)官方破解版V19.0.1.4下载
- 代理模式
- 风投与IT与中国
- iOS开发网络篇 一一 NSURLSessionDataTask实现大文件离线断点下载(重点)
- C#学习笔记之——写一个能算出今天是今年第几天的方法
- [JAVA]重载与重写的区别
- Java MySql简单使用
- 2370 小机房的树(lca)
- JAX-RS客户端WebClient的使用教程
- TRUNCATE命令
- 图片验证码(Struts2中使用)
- 【软工】开发模型