• iOS中大文件下载(单线程下载)


    主要是需要注意,在客服端发请求给服务器的时候,在请求头里是可以设置服务器返回的数据从哪开始,到哪结束的.

    当服务器响应客户端时,是可以拿到服务器返回数据具体类型以及大小的

    思路:

    在接收到服务器响应时,创建一个空文件,和一个跟空文件相关联的句柄对象

    然后,在接收到服务器返回的数据时,利用句柄对象,移动到文件末尾,将数据拼接到文件末尾

    在接受完服务器返回的数据后,关闭句柄

    #import <Foundation/Foundation.h>
    
    @interface ZYFileDownLoad : NSObject
    //所需要下载文件的远程URL(连接服务器的路径)
    @property (nonatomic, strong) NSString *urlStr;
    
    //文件的存储路径
    @property (nonatomic, strong) NSString *goalPath;
    
    //是否正在下载
    @property (nonatomic, readonly, getter= isDownLoading) BOOL downLoading;
    
    //监听下载进度
    @property (nonatomic, copy) void (^progressHandler)(double progress);
    
    //下载完成后的回调
    @property (nonatomic, copy) void (^finishHandler)();
    
    //下载失败后的回调
    @property (nonatomic, copy) void (^failureHandler)(NSError *error);
    
    //开始下载
    - (void)start;
    
    //暂停下载
    - (void)pause;
    
    @end
    
    
    
    
    /*
        文件一般保存在下面的地址,Documents路径下的文件需要同步,文件大的话消耗性能,tmp路径下随时会被删除
        所以一般保存在LibraryCaches路径下
     
        获取此路径:
        NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
        NSString *filepath = [caches stringByAppendingPathComponent:@"文件名.后缀名"];
     */
    #import "ZYFileDownLoad.h"
    
    @interface ZYFileDownLoad() <NSURLConnectionDataDelegate>
    //当前已下载的数据长度
    @property (nonatomic, assign) long long currentLength;
    
    //连接对象
    @property (nonatomic, strong) NSURLConnection *connection;
    
    //总的文件长度
    @property (nonatomic, assign) long long totalLength;
    
    //写入文件句柄
    @property (nonatomic, strong) NSFileHandle *writeHandle;
    
    @end
    
    @implementation ZYFileDownLoad
    - (void)start
    {
        [self.urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSURL *url = [NSURL URLWithString:self.urlStr];
        
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
        
        //设置请求头信息,这里表示,此次数据范围是currentProgress 到文件最后(也就是只设置开头从什么地方下载)
        NSString *value = [NSString stringWithFormat:@"bytes=%lld-",self.currentLength];
        [request setValue:value forHTTPHeaderField:@"Range"];
        
        self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
        
        _downLoading = YES;
    }
    
    - (void)pause
    {
        [self.connection cancel];
        self.connection = nil;
        _downLoading = NO;
    }
    
    #pragma mark ----NSURLConnectionDataDelegate
    
    //请求错误(失败)的时候调用
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    {
        if (self.failureHandler) {
            self.failureHandler(error);
        }
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        if (self.totalLength) return;   //当已经回复过响应了,就无需再次回复(主要用于暂停下载,再回复下载操作)
        
        //创建一个空的文件到沙盒中
        NSFileManager *manager = [NSFileManager defaultManager];
        [manager createFileAtPath:self.goalPath contents:nil attributes:nil];
        
        ////创建写数据的文件句柄
        self.writeHandle = [NSFileHandle fileHandleForWritingAtPath:self.goalPath];
        
        //获得完整文件的长度(服务器响应客户端时,会返回具体具体的文件长度)
        self.totalLength = response.expectedContentLength;
    }
    
    
    //当接受到服务器的数据就会调用(可能会被调用多次, 每次调用只会传递部分数据)
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        self.currentLength += [data length];  //下载完成,累加长度
        
        //进度
        double progress = (double)self.currentLength / self.totalLength;
        
        //通过block回调,可以执行block里面的操作
        if (self.progressHandler) {
            self.progressHandler(progress);
        }
        
        //移动文件尾部,往尾部追加数据
        [self.writeHandle seekToEndOfFile];
        [self.writeHandle writeData:data];
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
        //下载完毕,请客属性
        self.currentLength = 0;
        self.totalLength = 0;
        
        if (self.currentLength == self.totalLength) {
            //下载完毕,关闭连接
            [self.writeHandle closeFile];
            self.writeHandle = nil;
        }
        
        if (self.finishHandler) {
            self.finishHandler();
        }
    }
    @end
    
  • 相关阅读:
    SpringMVC注解控制器详解
    在自己的服务器上安装GitBook
    基于UDP协议的网络编程
    RabbitMQ安装使用详解
    Python3.4 + Django1.7.7 搭建简单的表单并提交
    暴力枚举 UVA 10976 Fractions Again?!
    暴力枚举 UVA 725 Division
    思维 UVALive 3708 Graveyard
    DFS(剪枝) POJ 1011 Sticks
    DFS+模拟 ZOJ 3861 Valid Pattern Lock
  • 原文地址:https://www.cnblogs.com/ziyi--caolu/p/4674944.html
Copyright © 2020-2023  润新知