美文网首页
文件下载和离线断点下载

文件下载和离线断点下载

作者: 高乔人 | 来源:发表于2019-05-14 15:55 被阅读0次

不知道说什么,直接上代码吧
/*
文件下载的 思路及问题:
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

相关文章

网友评论

      本文标题:文件下载和离线断点下载

      本文链接:https://www.haomeiwen.com/subject/sizsaqtx.html