项目需求
我们公司项目是APP和硬件相连,然后通过WI-FI,硬件做sever,取回硬件里我们想要取回的东西,所以我选择用断点续传
- 断点续传就是从文件上次中断的地方开始重新下载或上传数据,而不是从文件开头。(例如你上次下载到74%,断开连接了,重新连接它会从74%开始下载,不用从头开始,较适用于下载大型文件)
- 断点续传主要依赖于HTTP头部定义的Range来完成的
- 断点续传原理可以查看https://www.ibm.com/developerworks/cn/mobile/mo-cn-breakpoint/index.html 非常简单明了
我用的断点续传,是网上大多数人都用的#import "MQLResumeManager.h" 大家可以谷歌一下,很多都有我就不一一赘述了 ,其实这篇文章,也只是我自己留着看的,因为网上写的比我好的挺多的,我只是想详细的研究一下封装好的代码
if (downloadedBytes > 0) {
//已经下载过,所以downloadedBytes=12345,Range: bytes=12345”表示请求资源开头 12345 字节之后的部分
NSString *requestRange = [NSString stringWithFormat:@"bytes=%llu-", downloadedBytes];
[request setValue:requestRange forHTTPHeaderField:@"Range"];
}else{
//第一次下载没有已下载数据downloadedBytes为空
int fileDescriptor = open([self.targetPath UTF8String], O_CREAT | O_EXCL | O_RDWR, 0666);
if (fileDescriptor > 0) {
close(fileDescriptor);
}
} ```
- 几个属性我们要先搞清楚
```@property (nonatomic, strong) NSURLSession *session; //注意一个session只能有一个请求任务
@property (nonatomic, readwrite, retain) NSError *error; //请求出错
@property (nonatomic, readwrite, copy) completionBlock completionBlock;
@property (nonatomic, readwrite, copy) progressBlock progressBlock;
@property (nonatomic, strong) NSURL *url; //文件资源地址
@property (nonatomic, strong) NSString *targetPath; //文件存放路径
@property long long totalContentLength; //文件总大小
@property long long totalReceivedContentLength; //已下载大小 ```
``` - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data{
//根据status code的不同,做相应的处理
NSHTTPURLResponse *response = (NSHTTPURLResponse*)dataTask.response;
if (response.statusCode == 200) {
self.totalContentLength = dataTask.countOfBytesExpectedToReceive;
}else if (response.statusCode == 206){
NSString *contentRange = [response.allHeaderFields valueForKey:@"Content-Range"];
if ([contentRange hasPrefix:@"bytes"]) {
//Content-Range: bytes 12367-200000/200000”说明了返回提供了请求资源所在的原始实体内的位置,还给出了整个资源的长度。
NSArray *bytes = [contentRange componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" -/"]];
if ([bytes count] == 4) {
//self.totalCotentLength=200000;
self.totalContentLength = [[bytes objectAtIndex:3] longLongValue];
}
}
}else if (response.statusCode == 416){
NSString *contentRange = [response.allHeaderFields valueForKey:@"Content-Range"];
if ([contentRange hasPrefix:@"bytes"]) {
NSArray *bytes = [contentRange componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" -/"]];
if ([bytes count] == 3) {
self.totalContentLength = [[bytes objectAtIndex:2] longLongValue];
if (self.totalReceivedContentLength == self.totalContentLength) {
//说明已下完
//更新进度
self.progressBlock();
}else{
//416 Requested Range Not Satisfiable
self.error = [[NSError alloc]initWithDomain:[self.url absoluteString] code:416 userInfo:response.allHeaderFields];
}
}
}
return;
}else{
//其他情况还没发现
return;
}
//向文件追加数据
NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:self.targetPath];
[fileHandle seekToEndOfFile]; //将节点跳到文件的末尾
[fileHandle writeData:data];//追加写入数据
[fileHandle closeFile];
//更新进度
self.totalReceivedContentLength += data.length;
self.progressBlock();
}```
- 206 Partial Content 客户发送了一个带有Range头的GET请求,服务器完成了它。
- 416 Requested Range Not Satisfiable 服务器不能满足客户在请求中指定的Range头。
网友评论