多线程断点下载

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值