iOS的断点续传原理和初步实现

原理:

请求时在请求头中添加Range字段,标识下载的起始位置,将下载的数据添加到本地文件中,直到下载完。

使用:

[[BEBreakPointResumeManager shareInstance] setUrlWithUrlStirng:@"http://excample.com/xxx.zip"];
    [BEBreakPointResumeManager shareInstance].receivingDataBlock = ^void(NSData *receivingData) {
        NSLog(@"receivingData:%ld", receivingData.length);
    };

简单实现:

BEBreakPointResumeManager.h
//
//  BEBreakPointResumeManager.h
//  BE_断点续传
//
//  Created by luopengfei on 2017/4/18.
//  Copyright © 2017年 luopengfei. All rights reserved.
//

#import 

/**
 断点续传的管理类
 */

@interface BEBreakPointResumeManager : NSObject

+ (BEBreakPointResumeManager *)shareInstance  NS_DEPRECATED(10_0, 10_0, 2_0, 11, "不能写成单例,整个app又不是只有一个下载任务") ;

- (void)setUrlWithUrlStirng:(NSString *)urlStirng localFilePathString:(NSString *)filePathString;

@property (nonatomic, copy) void(^downloadFinishBlock)();

@property (nonatomic, copy) void(^receivingDataBlock)(NSData *receivingData);

@end

BEBreakPointResumeManager.m
//
//  BEBreakPointResumeManager.m
//  BE_断点续传
//
//  Created by luopengfei on 2017/4/18.
//  Copyright © 2017年 luopengfei. All rights reserved.
//

#import "BEBreakPointResumeManager.h"

@interface BEBreakPointResumeManager() /***/ 
@property (nonatomic, strong) NSURLConnection *urlConnection;
@property (nonatomic, strong) NSFileHandle *fileHandle;     // 文件操作,读写文件的句柄
//@property (nonatomic, strong) NSFileManager *fileManager; // 文件属性

@property (nonatomic, assign) long long expectedFileLength; // 下载资源的整个大小
@property (nonatomic, assign) long long localFileLength;    // 已下载资源的大小
@end

@implementation BEBreakPointResumeManager

+ (BEBreakPointResumeManager *)shareInstance {
    
    static BEBreakPointResumeManager *beBreakPointResumeManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        beBreakPointResumeManager = [[super allocWithZone:NULL] init];
        [beBreakPointResumeManager breakPointResumeInition];
    });
    
    return beBreakPointResumeManager;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    
    return [BEBreakPointResumeManager shareInstance];
}
- (id)copyWithZone:(NSZone *)zone {
    return [BEBreakPointResumeManager shareInstance];
}


/**
 初始化
 */
- (void)breakPointResumeInition {
    
    
}

- (void)setUrlWithUrlStirng:(NSString *)urlStirng localFilePathString:(NSString *)filePathString {
    
    self.localFileLength = 0;
    NSFileManager *fm = [NSFileManager defaultManager];
    if ([fm fileExistsAtPath:filePathString]) {
        
        self.fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePathString];
        self.localFileLength = [self.fileHandle readDataToEndOfFile].length;
    } else {
        self.localFileLength = [fm createFileAtPath:filePathString contents:nil attributes:nil];
    }
    
    
    NSMutableURLRequest *urlRequset = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[urlStirng stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
    
    //bytes=30650252-
    [urlRequset setValue:[NSString stringWithFormat:@"bytes=%lld-", self.localFileLength] forHTTPHeaderField:@"Range"];
    
    _urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequset delegate:self];
    
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response {
    
    if (!self.expectedFileLength) {
        self.expectedFileLength = response.expectedContentLength;
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    
//    [self.fileHandle seekToEndOfFile]; //默认
    [self.fileHandle writeData:data];
    
    _localFileLength += data.length;
    
    if (self.receivingDataBlock) {
        self.receivingDataBlock(data);
    }
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    
    [self.urlConnection cancel];
    
    if (self.downloadFinishBlock) {
        self.downloadFinishBlock();
    }
}


@end

你可能感兴趣的:(iOS的断点续传原理和初步实现)