不知道说什么,直接上代码吧
/*
文件下载的 思路及问题:
NSURLSessionDataTask 下载文件
(1),内存暴涨 NSFileHandle边接收数据边写沙盒
(2)监听文件的下载进度 已经下载的文件数据/请求的总数据(响应头)
(3)常用操作: 开始|暂停|取消|下载
(4)断点下载:设置请求头 "Range"
(5)进度信息不正确,(响应头中的expectedContentLength并不一定是文件的大小,而是本次请求的文件数据的大小)
(6)文件不完整:
①判断只有第一次 下载的时候才创建空文件
②移动文件句柄指针到文件末尾
*/
/*
NSFileHandle 文件句柄(指针) 移动的添加数据 不会覆盖上一次添加的数据 (边写边移动)
步骤:
1:创建空的文件
2.创建文件句柄指针指向该文件
3.接收到数据的时候,使用该句柄来写数据
4.数据写完的时候,关闭句柄指针
*/
define KfullPath [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"xhw.mp4"]
@interface ViewController ()<NSURLSessionDataDelegate>
@property (nonatomic,strong) NSMutableData *fileData;
@property (nonatomic,assign) NSInteger totalSize;//文件总大小
@property (nonatomic,assign) NSInteger currentSize;//当前获取d文件的大小
@property (nonatomic,strong) NSFileHandle *fileHandle;
@property (nonatomic,strong) NSURLSessionDataTask *task;
@end
@implementation ViewController
- (NSURLSessionDataTask *)task{
if (!_task) {
//2.文件下载(大文件下载) 设置代理
//1 创建请求路径
NSURL *url = [NSURL URLWithString:@""];
//创建请求对象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//设置请求头信息(告诉对象只下载某一个部分数据)Range
/*
Range:
bytes = 0-100
tytes = -100 从文件开始到100
tytes = 400-100
tytes = 400- 这些格式都可以 但是格式必须是这几样
*/
NSString *header = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
[request setValue:header forHTTPHeaderField:@"Range"];
NSLog(@"请求下载的数据的范围:%@,",header);
//创建绘画对象
NSURLSession *session = [NSURLSession sessionWithConfiguration: [NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue: [NSOperationQueue mainQueue]];
//创建下载请求TASK
_task = [session dataTaskWithRequest:request];
//发送请求
}
return _task;
}
- (NSMutableData *)fileData{
if (!_fileData) {
_fileData = [[NSMutableData alloc] init];
}
return _fileData;
}
- (void)viewDidLoad {
[super viewDidLoad];
/**
1.图片下载 小文件下载(采用这个办法)
*/
//1.1.图片下载 小文件下载(采用这个办法)
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@""] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *img = [UIImage imageWithData:data];
NSLog(@"%@",img);
}] resume];
//得到沙盒中已经下载的文件的大小 这就是离线断点下载
NSDictionary *fileInfo = [[NSFileManager defaultManager] attributesOfItemAtPath:KfullPath error:nil];
self.currentSize = [fileInfo fileSize];
}
//接受到响应的时候调用
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
//文件总的大小 = 本次请求的数据大小 + 已经请求的数据大小
self.totalSize = response.expectedContentLength + self.currentSize;
//得到本次请求的文件数据大小 expectedContentLength期望的长度
//创建空文件 拼接路径
// NSString *fileName = [response suggestedFilename];
// NSString *cache = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
//拼接文件的存储路径 (沙盒路径) + 文件名
// NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"xhw.mp4"];
//防止反复创建空文件 覆盖上一次创建的文件
if (self.currentSize == 0) {
[[NSFileManager defaultManager] createFileAtPath:KfullPath contents:nil attributes:nil];
}
//创建文件句柄指针指向该文件 默认指向文件的开头
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:KfullPath];
self.fileHandle = fileHandle;
//移动文件句柄指针 指向文件的末尾 (第二次下载的时候)
[self.fileHandle seekToEndOfFile];
//告诉系统应该接收数据
completionHandler(NSURLSessionResponseAllow);
}
//告诉服务器 返回数据的时候调用,可能会调用多次
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
[self.fileHandle writeData:data];
self.currentSize += data.length;
CGFloat progress = self.currentSize/self.totalSize;
NSLog(@"%f",progress);
}
//下载完成或是失败的时候调用
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
[self.fileHandle closeFile];
}
//开始下载
- (void)star{
[_task resume];
NSLog(@"开始下载");
}
//暂停下载 可以回复下载的
- (void)stop{
[self.task suspend];
NSLog(@"暂停下载");
}
//取消下载
- (void)cancel{
[self.task cancel];//不能回复下载
//如果取消后还想接着原来的下载 调用test方法
NSLog(@"取消下载");
}
//回复下载
- (void)resume{
[self.task resume];
NSLog(@"回复下载");
}
- (void)test{
self.task = nil;
}
@end
还有一个方法是使用输出流
define KfullPath [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"xhw.mp4"]
@interface ViewController ()<NSURLSessionDataDelegate>
@property (nonatomic,strong) NSMutableData *fileData;
@property (nonatomic,assign) NSInteger totalSize;//文件总大小
@property (nonatomic,assign) NSInteger currentSize;//当前获取d文件的大小
//@property (nonatomic,strong) NSFileHandle *fileHandle;
@property (nonatomic,strong) NSURLSessionDataTask *task;
@property (nonatomic,strong) NSOutputStream *stream;
@end
@implementation ViewController
/*
文件下载的 思路及问题:
NSURLSessionDataTask 下载文件
(1),内存暴涨 NSFileHandle边接收数据边写沙盒
(2)监听文件的下载进度 已经下载的文件数据/请求的总数据(响应头)
(3)常用操作: 开始|暂停|取消|下载
(4)断点下载:设置请求头 "Range"
(5)进度信息不正确,(响应头中的expectedContentLength并不一定是文件的大小,而是本次请求的文件数据的大小)
(6)文件不完整:
①判断只有第一次 下载的时候才创建空文件
②移动文件句柄指针到文件末尾
*/
/*
NSFileHandle 文件句柄(指针) 移动的添加数据 不会覆盖上一次添加的数据 (边写边移动)
步骤:
1:创建空的文件
2.创建文件句柄指针指向该文件
3.接收到数据的时候,使用该句柄来写数据
4.数据写完的时候,关闭句柄指针
*/
- (NSURLSessionDataTask *)task{
if (!_task) {
//2.文件下载(大文件下载) 设置代理
//1 创建请求路径
NSURL *url = [NSURL URLWithString:@""];
//创建请求对象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//设置请求头信息(告诉对象只下载某一个部分数据)Range
/*
Range:
bytes = 0-100
tytes = -100 从文件开始到100
tytes = 400-100
tytes = 400- 这些格式都可以 但是格式必须是这几样
*/
NSString *header = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
[request setValue:header forHTTPHeaderField:@"Range"];
NSLog(@"请求下载的数据的范围:%@,",header);
//创建绘画对象
NSURLSession *session = [NSURLSession sessionWithConfiguration: [NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue: [NSOperationQueue mainQueue]];
//创建下载请求TASK
_task = [session dataTaskWithRequest:request];
//发送请求
}
return _task;
}
- (NSMutableData *)fileData{
if (!_fileData) {
_fileData = [[NSMutableData alloc] init];
}
return _fileData;
}
- (void)viewDidLoad {
[super viewDidLoad];
/**
1.图片下载 小文件下载(采用这个办法)
*/
//1.1.图片下载 小文件下载(采用这个办法)
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@""] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *img = [UIImage imageWithData:data];
NSLog(@"%@",img);
}] resume];
//得到沙盒中已经下载的文件的大小 这就是离线断点下载
NSDictionary *fileInfo = [[NSFileManager defaultManager] attributesOfItemAtPath:KfullPath error:nil];
self.currentSize = [fileInfo fileSize];
}
//接受到响应的时候调用
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
//文件总的大小 = 本次请求的数据大小 + 已经请求的数据大小
self.totalSize = response.expectedContentLength + self.currentSize;
//得到本次请求的文件数据大小 expectedContentLength期望的长度
//创建空文件 拼接路径
// NSString *fileName = [response suggestedFilename];
// NSString *cache = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
//拼接文件的存储路径 (沙盒路径) + 文件名
// NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"xhw.mp4"];
//防止反复创建空文件 覆盖上一次创建的文件
//if (self.currentSize == 0) {
// [[NSFileManager defaultManager] createFileAtPath:KfullPath contents:nil attributes:nil];
//}
//创建文件句柄指针指向该文件 默认指向文件的开头
//NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:KfullPath];
//self.fileHandle = fileHandle;
////移动文件句柄指针 指向文件的末尾 (第二次下载的时候)
//[self.fileHandle seekToEndOfFile];
//使用输出流 也可以
/* 参数说明:
* 第一个参数:指向文件的路径
*第二个参数:是否要追加数据
*如果制定路径的文件不存在,输出流会自动创建一个空文件
*/
NSOutputStream *stream = [[NSOutputStream alloc] initToFileAtPath:KfullPath append:YES];
self.stream = stream;
[stream open];
//告诉系统应该接收数据
completionHandler(NSURLSessionResponseAllow);
}
//告诉服务器 返回数据的时候调用,可能会调用多次
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
[self.stream write:data.bytes maxLength:data.length];
//[self.fileHandle writeData:data];
self.currentSize += data.length;
CGFloat progress = self.currentSize/self.totalSize;
NSLog(@"%f",progress);
}
//下载完成或是失败的时候调用
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
//关闭输出流
[self.stream close];
//[self.fileHandle closeFile];
}
//开始下载
- (void)star{
[_task resume];
NSLog(@"开始下载");
}
//暂停下载 可以回复下载的
- (void)stop{
[self.task suspend];
NSLog(@"暂停下载");
}
//取消下载
- (void)cancel{
[self.task cancel];//不能回复下载
//如果取消后还想接着原来的下载 调用test方法
NSLog(@"取消下载");
}
//回复下载
- (void)resume{
[self.task resume];
NSLog(@"回复下载");
}
- (void)test{
self.task = nil;
}
@end
网友评论