• iOS开发中多线程断点下载大文件


    主要思想,就是创建一个与目标文件等大小的空白文件,然后分段往这个空白文件中写入数据。

    可以通过发送HEAD请求,获得服务器中文件的具体大小,然后再将这样的长度分割成若干等大的数据块,在发送get请求时,通过设置

    请求头信息,可以确定好单个线程中下载文件的起始长度和结束长度。

    比如说,目标文件大小事900M,在下载时,开三条线程来下载,size = 300。那么第一条线程就该是0~~299M的任务

    第二条线程是300~~599M的任务,第三条则是600M~~最后的大小,当不能整除时,每个size+1,以免造成错误。

    在写入文件的适合(这是边下载边写入),通过文件句柄(NSFileHandle)移动到当前下载的文件的末尾,再写入.

    当下载完毕,需要关闭当前的文件句柄。

    @interface ZYFileDownLoad : NSObject
    {
        BOOL _downLoading;
    }
    //是否正在下载
    @property (nonatomic, readonly, getter=isDownLoading) BOOL downLoading;
    //目标路径,也就是存储路径
    @property (nonatomic, copy) NSString *goalPath;
    //下载资源的url
    @property (nonatomic, copy) NSString *urlStr;
    //下载进度
    @property (nonatomic, copy) void (^progressHandler)(double progress);
    
    //开始下载
    - (void)start;
    
    //结束下载
    - (void)pause;
    @end
    
    
    #import "ZYFileDownLoad.h"
    
    @implementation ZYFileDownLoad
    
    @end
    
    #import "ZYFileDownLoad.h"
    
    @interface ZYMultiFileDownLoad : ZYFileDownLoad
    
    @end
    
    
    #import "ZYMultiFileDownLoad.h"
    #import "ZYSingleDownLoad.h"
    #define ZYMaxDownLoadCount 3
    
    @interface ZYMultiFileDownLoad ()
    @property (nonatomic, strong) NSMutableArray *singleDownLoads;
    @property (nonatomic, assign) long long totalLength;
    @end
    
    @implementation ZYMultiFileDownLoad
    - (void)getFileSize
    {
        //发送一个HEAD请求,得到服务器响应头中数据的具体信息 Content-Length
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.urlStr]];
        request.HTTPMethod = @"HEAD";
        NSURLResponse *response = nil;
        //也可发送异步请求获得信息
        [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
        //取得文件大小
        self.totalLength = response.expectedContentLength;
    }
    
    - (NSMutableArray *)singleDownLoads
    {
        if (_singleDownLoads == nil) {
            _singleDownLoads = [NSMutableArray array];
            
            [self getFileSize];
            
            long long size = 0;
            
            //每条路径的下载量
            if (self.totalLength % ZYMaxDownLoadCount == 0) {
                size = self.totalLength / ZYMaxDownLoadCount;
            }
            else{
                size = self.totalLength / ZYMaxDownLoadCount + 1;
            }
            
            //创建n个下载器
            for (int i = 0; i < ZYMaxDownLoadCount; i++) {
                ZYSingleDownLoad *singleDownLoad = [[ZYSingleDownLoad alloc] init];
                singleDownLoad.urlStr = self.urlStr;
                singleDownLoad.goalPath = self.goalPath;
                singleDownLoad.beginLength = i * size;
                singleDownLoad.endLength =  (i + 1) * size - 1;
                singleDownLoad.progressHandler = ^(double progress){
                    //在这里可以设置进度操作
                };
                [_singleDownLoads addObject:singleDownLoad];
                
                // 创建一个跟服务器文件等大小的临时文件
                [[NSFileManager defaultManager] createFileAtPath:self.goalPath contents:nil attributes:nil];
                
                // 让self.goalPath文件的长度是self.totalLengt
                NSFileHandle *writeHandle = [NSFileHandle fileHandleForWritingAtPath:self.goalPath];
                [writeHandle truncateFileAtOffset:self.totalLength];
            }
        }
        return _singleDownLoads;
    }
    
    - (void)start
    {
        [self.singleDownLoads makeObjectsPerformSelector:@selector(start)];
        _downLoading = YES;
    }
    
    - (void)pause
    {
        [self.singleDownLoads makeObjectsPerformSelector:@selector(pause)];
        _downLoading = NO;
    }
    @end
    
    @interface ZYSingleDownLoad : ZYFileDownLoad
    
    @property (nonatomic, assign) long long beginLength;
    @property (nonatomic, assign) long long endLength;
    @end
    
    
    #import "ZYSingleDownLoad.h"
    
    @interface ZYSingleDownLoad() <NSURLConnectionDataDelegate>
    @property (nonatomic, assign) long long currentLength;
    
    @property (nonatomic, strong) NSURLConnection *connection;
    
    @property (nonatomic, strong) NSFileHandle *writeHandle;
    
    @end
    
    @implementation ZYSingleDownLoad
    
    - (NSFileHandle *)writeHandle
    {
        if (!_writeHandle) {
            _writeHandle = [NSFileHandle fileHandleForWritingAtPath:self.goalPath];
        }
        return _writeHandle;
    }
    
    - (void)start
    {
        NSURL *url = [NSURL URLWithString:self.urlStr];
        
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
        //设置请求体,从哪个数据段开始下载
        NSString *values = [NSString stringWithFormat:@"bytes=%lld-%lld",self.beginLength + self.currentLength,self.endLength];
        [request setValue:values forHTTPHeaderField:@"Range"];
        
        self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
        
        _downLoading = YES;
    }
    
    - (void)pause
    {
        [self.connection cancel];
        
        self.connection = nil;
    }
    
    #pragma mark --------  NSURLConnectionDataDelegate
    
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        // 移动到文件的尾部
        [self.writeHandle seekToFileOffset:self.beginLength + self.currentLength];
        // 从当前移动的位置(文件尾部)开始写入数据
        [self.writeHandle writeData:data];
        
        // 累加长度
        self.currentLength += data.length;
        
        // 打印下载进度
        double progress = (double)self.currentLength / (self.endLength - self.beginLength);
        if (self.progressHandler) {
            self.progressHandler(progress);
        }
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
        // 清空属性值
        self.currentLength = 0;
        
        // 关闭连接
        [self.writeHandle closeFile];
        self.writeHandle = nil;
    }
    
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    {
        
    }
    @end
    
  • 相关阅读:
    使用Kubeadm安装Kubernetes【单Master节点】
    spark on yarn内存和CPU分配
    spark on yarn提交后vcore数不对
    Win7_64位MyEclipse2015提交mapreduce到CDH5.10.0任务失败
    我对Map端spill的理解
    mapreduce on yarn简单内存分配解释
    namenode无法启动
    全栈编程@luboke.com原创go语言体系课
    基于go语言结合微信小程序开发的微商城系统
    微信小程序登陆流程图时序图
  • 原文地址:https://www.cnblogs.com/ziyi--caolu/p/4676223.html
Copyright © 2020-2023  润新知