多线程断点下载

来源:互联网 发布:windows损坏文件 编辑:程序博客网 时间:2024/05/20 19:19
1.文件下载类(父类)
////  FileDownloader.h//  文件下载器// 一个FileDownloader下载一个文件#import <Foundation/Foundation.h>@interface FileDownloader : NSObject{    BOOL _downloading;}/** * 所需要下载文件的远程URL(连接服务器的路径) */@property (nonatomic, copy) NSString *url;/** * 文件的存储路径(文件下载到什么地方) */@property (nonatomic, copy) NSString *destPath;/** * 是否正在下载(有没有在下载, 只有下载器内部才知道) */@property (nonatomic, readonly, getter = isDownloading) BOOL downloading;/** * 用来监听下载进度 */@property (nonatomic, copy) void (^progressHandler)(double progress);/** * 开始(恢复)下载 */- (void)start;/** * 暂停下载 */- (void)pause;@end

////  FileDownloader.m//  文件下载器//#import "FileDownloader.h"@implementation FileDownloader@end
2.单点下载类
////  FileSingleDownloader.h#import "FileDownloader.h"@interface FileSingleDownloader : FileDownloader/** *  下载的范围(开始位置) */@property(nonatomic,assign)long long begin;/** *  下载的范围(结束位置) */@property(nonatomic,assign)long long end;@end

////  FileSingleDownloader.m#import "FileSingleDownloader.h"@interface FileSingleDownloader() <NSURLConnectionDataDelegate>/** *  连接对象 */@property(nonatomic,strong)NSURLConnection *conn;/** *  写数据的文件句柄 */@property(nonatomic,strong)NSFileHandle *writeHandle;/** *  当前已下载的数据的长度 */@property(nonatomic,assign)long long currentLength;@end@implementation FileSingleDownloader- (NSFileHandle *)writeHandle{    if (!_writeHandle) {        _writeHandle = [NSFileHandle fileHandleForWritingAtPath:self.destPath];    }    return _writeHandle;}/** *  开始(恢复)下载 */- (void)start{    NSURL *url = [NSURL URLWithString:self.url];    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];        //设置请求头    NSString *value = [NSString stringWithFormat:@"bytes=%lld-%lld",self.begin+self.currentLength,self.end];    [request setValue:value forHTTPHeaderField:@"Range"];        self.conn = [NSURLConnection connectionWithRequest:request delegate:self];        _downloading = YES;}/** *  暂停 */- (void)pause{    [self.conn cancel];    self.conn = nil;        _downloading = NO;}#pragma mark - NSURLConnectionDataDelegate/** *  1.当接受到服务器的响应的就会调用 */- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{}/** *  2.当接受到服务器返回的数据就会调用(可能会被调用多次,每次只会传递部分数据) */- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{        //移到到文件的尾部    [self.writeHandle seekToFileOffset:self.begin + self.currentLength];    //从当前移动的位置(文件尾部)开始写入数据    [self.writeHandle writeData:data];        //2.累计已下载的数据的长度    self.currentLength += data.length;        //打印下载进度   double progress = (double)self.currentLength / (self.end-self.begin);    if (self.progressHandler) {        self.progressHandler(progress);    }}/** *  3.当服务器的数据接受完毕后就会调用 */- (void)connectionDidFinishLoading:(NSURLConnection *)connection{    //清空属性值    self.currentLength = 0;        //关闭连接(不再输入数据到文件中)    [self.writeHandle closeFile];    self.writeHandle = nil;}/** *  请求失败的时候调用(请求超时、断网、没有网。一般都是客户端错误) */- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{}@end
3.多点下载
////  FileMultiDownloader.h//  文件下载//  多线程下载器(利用FileMultiDownloader能开启多个线程同时下载一个文件)//  一个多线程下载器 只 下载一个文件#import "FileDownloader.h"@interface FileMultiDownloader : FileDownloader@end

////  FileMultiDownloader.m#import "FileMultiDownloader.h"#import "FileSingleDownloader.h"#define MaxDownloadCount 3@interface FileMultiDownloader()@property(nonatomic,strong)NSMutableArray *singleDownloaders;@property(nonatomic,assign)long long totalLength;@end@implementation FileMultiDownloader/** *  获得要下载的文件的大小 */- (void)getFilesize{    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.url]];    request.HTTPMethod = @"HEAD";        NSURLResponse *response = nil;    [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];    self.totalLength = response.expectedContentLength;}- (NSMutableArray *)singleDownloaders{    if (!_singleDownloaders) {        _singleDownloaders = [NSMutableArray array];                //获取文件大小        [self getFilesize];                //每条线程的下载量        long long size = 0;        if (self.totalLength % MaxDownloadCount == 0) {            size = self.totalLength / MaxDownloadCount;        }else{            size = self.totalLength / MaxDownloadCount + 1;        }                //创建N个下载器        for (int i=0; i<MaxDownloadCount; i++) {            FileSingleDownloader *singleDownloader = [[FileSingleDownloader alloc] init];            singleDownloader.url = self.url;            singleDownloader.destPath = self.destPath;            singleDownloader.begin = i * size;            singleDownloader.end = singleDownloader.begin + size - 1;            singleDownloader.progressHandler = ^(double progress){                //打印下载进度//                NSLog(@"%d----%f",i,progress);            };                        [_singleDownloaders addObject:singleDownloader];        }                //创建一个跟服务器文件等大小的临时文件        [[NSFileManager defaultManager] createFileAtPath:self.destPath contents:nil attributes:nil];                //让self.destPath文件的长度是 self.totalLength        NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:self.destPath];        [handle truncateFileAtOffset:self.totalLength];    }    return _singleDownloaders;}/** *  开始(恢复)下载 */- (void)start{    [self.singleDownloaders makeObjectsPerformSelector:@selector(start)];        _downloading = YES;}/** *  暂停 */- (void)pause{    [self.singleDownloaders makeObjectsPerformSelector:@selector(pause)];        _downloading = NO;}@end
4.控制器调用
#import "ViewController.h"#import "FileMultiDownloader.h"@interface ViewController ()//下载器@property(nonatomic,strong)FileMultiDownloader *fileMultiDownloader;@end@implementation ViewController- (FileMultiDownloader *)fileDownloader{    if (!_fileMultiDownloader) {        _fileMultiDownloader = [[FileMultiDownloader alloc] init];                //需要下载的远程文件URL        _fileMultiDownloader.url = @"https://xxxx.com/images.zip";        //文件保存到什么地方        NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject];        NSString *filepath = [caches stringByAppendingPathComponent:@"images.zip"];        _fileMultiDownloader.destPath = filepath;    }    return _fileMultiDownloader;}- (void)viewDidLoad {    [super viewDidLoad];}- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{    //开始下载    [self.fileMultiDownloader start];}@end

0 0
原创粉丝点击