NSURLConnection,NSURLSession断点续传的实现以及对比

8 篇文章 0 订阅

1, NSURLConnection实现断点续传

首先明确几个关键点:

1, cancel方法.
   首先NSURLConnection有一个cancel方法,可以取消正在进行的下载操作,但是取消后无法再恢复当前下载链接.(这个和操作队列的挂起是本质区别的). 当重现建立下载链接的时候,又是从头开始下载了.
2, http请求头,range字段.
   通过设定renge头,我们可以限定下载资源的哪一部分.
   实例代码如下:
        NSString *range = [NSString stringWithFormat:@"bytes=%lld-",self.currentFileSize];
        [request setValue:range forHTTPHeaderField:@"Range"];
3, 思路:
     其实基于以上两点,我们的思路就已经有了:
     当我们再次发起请求下载资源的时候:
     1,首先我们应该检查一下本地是否已近有这个文件了,文件的长度是多少等等.
     2,然后在通过发送"HEAD" 请求,来获得服务端资源的一些信息:文件长度,类型等等
     3,基于以上两步操作,对比本地文件长度和服务端文件长度,这样就知道资源的下载进度了,从而计算出 range 头.
    4,再次发送带 "range头"的请求.继续下载文件.实现断点续传.

直接上代码:


#import "ViewController.h"
#import <NewsstandKit/NewsstandKit.h>
@interface ViewController ()<NSURLConnectionDataDelegate>
// 保存下载文的件路径
@property(nonatomic,copy) NSString *destinationPath;
// 文件总大小
@property(nonatomic,assign) long  long expectedContentLenght;
// 当前接收文件大小
@property(nonatomic,assign) long  long currentFileSize;
// 文件输出流
@property(nonatomic,strong) NSOutputStream *fileStream;
// 请求链接对象
@property(nonatomic,strong) NSURLConnection *connection;
@end

@implementation ViewController
/**
 *  暂停下载
 */
- (IBAction)pauseDownLoad {
    [self.connection cancel];
}

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        // url 字符串
        NSString *urlStr = @"http://localhost/图片浏览器.mp4";
        // 添加百分号转义
        urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        // 请求路径
        NSURL *url = [NSURL URLWithString:urlStr];

        // 检查服务器文件信息
        [self checkServerFileInfo:url];
        // 检查本地文件信息
        self.currentFileSize =[self checkLocalFileInfo];
        // 文件大小相等
        if (self.currentFileSize == self.expectedContentLenght) {
            NSLog(@"下载完成");
            return;
        }
        // 断点续传---一定不能使用缓存数据
        // 请求对象
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:15.0];
        // 创建 range 头
        NSString *range = [NSString stringWithFormat:@"bytes=%lld-",self.currentFileSize];
        [request setValue:range forHTTPHeaderField:@"Range"];
        // 建立连接,立即启动
        self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
        // 启动 runLoop
        [[NSRunLoop currentRunLoop] run];
    });
}

// 检查服务器的文件信息
- (void)checkServerFileInfo:(NSURL *)url{
    // 创建请求对象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 设置请求方法
    request.HTTPMethod = @"HEAD";

    NSURLResponse *response = nil;
    // 发送同步请求(这里必须要用同步)
    [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
    // 得到服务器响应
    // 1> 目标文件大小
    self.expectedContentLenght = response.expectedContentLength;
    // 2> 保存文件路径
    self.destinationPath = [NSTemporaryDirectory() stringByAppendingPathComponent:response.suggestedFilename];
}

// 检查本地文件的信息
- (long long)checkLocalFileInfo{
    // 获得文件管理对象
    NSFileManager *fileManager = [NSFileManager defaultManager];
    // 记录本地文件的大小
    long long fileSize = 0;
    // 判断文件是否存在
    if([fileManager fileExistsAtPath:self.destinationPath]) {
        // 文件存在,则获得文件信息
        NSDictionary *attr = [fileManager attributesOfItemAtPath:self.destinationPath error:NULL];
        // 直接从字典中获得文件大小
        fileSize = attr.fileSize;
    }
    // 如果大于服务器文件大小,直接删除
    if(fileSize > self.expectedContentLenght) {
        [fileManager removeItemAtPath:self.destinationPath error:NULL];
        fileSize = 0;
    }
    return fileSize;
}

#pragma mark - NSURLConnectionDataDelegate 代理方法
/**
 *  接收到服务器响应的时候调用(状态行和响应头)
 */
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
//    NSLog(@"response = %@",response);
    // 根据文件名 创建输出流对象
    self.fileStream = [NSOutputStream outputStreamToFileAtPath:self.destinationPath append:YES];
    // 打开流
    [self.fileStream open];
}

/**
 * 接收到服务器返回的数据时调用,可能会被调用多次(所有的 data 的数据都是按顺序传递过来的)
 */
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    self.currentFileSize += data.length;
    // 计算进度值
    CGFloat progress = (CGFloat)self.currentFileSize / self.expectedContentLenght;
    NSLog(@"接收到数据 = %f",progress);
    // 拼接数据
    [self.fileStream write:data.bytes maxLength:data.length];
}

/**
 *  网络请求结束调用(断开网络)
 */
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSLog(@"下载完成");
    // 关闭流
    [self.fileStream close];
}
/**
 *  网络连接发生错误的时候调用(任何网络请求都有可能出现错误)
 *  在实际开发中一定要进行出错处理
 */
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"error = %@",error);
    // 关闭流
    [self.fileStream close];
}
@end

2, NSURLSession实现断点续传

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值