zoukankan      html  css  js  c++  java
  • iOS 文件下载

    最为原始的文件下载
    第一步:
    使用MD5对url加密
    NSString+Password.h

    #import <Foundation/Foundation.h>
    
    @interface NSString (Password)
    
    /**
     *  32位MD5加密
     *
     *  @return 32位MD5加密结果
     */
    - (NSString *)MD5;
    
    /**
     *  SHA1加密
     *
     *  @return SHA1加密结果
     */
    - (NSString *)SHA1;
    
    @end
    
    #import "NSString+Password.h"
    #import <CommonCrypto/CommonDigest.h>
    
    @implementation NSString (Password)
    
    #pragma mark 使用MD5加密字符串
    - (NSString *)MD5
    {
        const char *cStr = [self UTF8String];
        unsigned char digest[CC_MD5_DIGEST_LENGTH];
    
        CC_MD5(cStr, strlen(cStr), digest);
    
        NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    
        for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
            [result appendFormat:@"%02x", digest[i]];
        }
    
        return result;
    }
    
    #pragma mark 使用SHA1加密字符串
    - (NSString *)SHA1
    {
        const char *cStr = [self UTF8String];
        NSData *data = [NSData dataWithBytes:cStr length:self.length];
        uint8_t digest[CC_SHA1_DIGEST_LENGTH];
    
        CC_SHA1(data.bytes, data.length, digest);
    
        NSMutableString *result = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
    
        for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
            [result appendFormat:@"%02x", digest[i]];
        }
    
        return result;
    }
    
    @end
    

    封装下载工具类

    FileDownload
    #import <Foundation/Foundation.h>
    
    @interface FileDownload : NSObject
    
    - (void)downloadFileWithURL:(NSURL *)url completion:(void (^)(UIImage *image))completion;
    @end
    #import "FileDownload.h"
    #import "NSString+Password.h"
    
    #define kTimeOut        2.0f
    // 每次下载的字节数
    #define kBytesPerTimes  20250
    
    @interface FileDownload()
    @property (nonatomic, strong) NSString *cacheFile;
    @property (nonatomic, strong) UIImage *cacheImage;
    @end
    
    @implementation FileDownload
    /**
     为了保证开发的简单,全部方法都不使用多线程,全部的注意力都保持在文件下载上
    
     在开发中假设碰到比較绕的计算问题时,建议:
     1> 測试数据不要太大
     2> 測试数据的数值变化,可以用笔算计算出准确的数值
     3> 编写代码对比測试
    
     */
    //- (NSString *)cacheFile
    //{
    //    if (!_cacheFile) {
    //        NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
    //        _cacheFile = [cacheDir stringByAppendingPathComponent:@"123.png"];
    //    }
    //    return _cacheFile;
    //}
    - (UIImage *)cacheImage
    {
        if (!_cacheImage) {
            _cacheImage = [UIImage imageWithContentsOfFile:self.cacheFile];
        }
        return _cacheImage;
    }
    
    - (void)setCacheFile:(NSString *)urlStr
    {
        NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
        urlStr = [urlStr MD5];
    
        _cacheFile = [cacheDir stringByAppendingPathComponent:urlStr];
    }
    
    - (void)downloadFileWithURL:(NSURL *)url completion:(void (^)(UIImage *image))completion
    {
        // GCD中的串行队列异步方法
        dispatch_queue_t q = dispatch_queue_create("cn.itcast.download", DISPATCH_QUEUE_SERIAL);
    
        dispatch_async(q, ^{
            NSLog(@"%@", [NSThread currentThread]);
    
            // 把对URL进行MD5加密之后的结果当成文件名称
            self.cacheFile = [url absoluteString];
    
            // 1. 从网络下载文件,须要知道这个文件的大小
            long long fileSize = [self fileSizeWithURL:url];
            // 计算本地缓存文件大小
            long long cacheFileSize = [self localFileSize];
    
            if (cacheFileSize == fileSize) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    completion(self.cacheImage);
                });
                NSLog(@"文件已经存在");
                return;
            }
    
            // 2. 确定每一个数据包的大小
            long long fromB = 0;
            long long toB = 0;
            // 计算起始和结束的字节数
            while (fileSize > kBytesPerTimes) {
                // 20480 + 20480
                //
                toB = fromB + kBytesPerTimes - 1;
    
                // 3. 分段下载文件
                [self downloadDataWithURL:url fromB:fromB toB:toB];
    
                fileSize -= kBytesPerTimes;
                fromB += kBytesPerTimes;
            }
            [self downloadDataWithURL:url fromB:fromB toB:fromB + fileSize - 1];
    
            dispatch_async(dispatch_get_main_queue(), ^{
                completion(self.cacheImage);
            });        
        });
    }
    
    #pragma mark 下载指定字节范围的数据包
    /**
     NSURLRequestUseProtocolCachePolicy = 0,        // 默认的缓存策略,内存缓存
    
     NSURLRequestReloadIgnoringLocalCacheData = 1,  // 忽略本地的内存缓存
     NSURLRequestReloadIgnoringCacheData
     */
    - (void)downloadDataWithURL:(NSURL *)url fromB:(long long)fromB toB:(long long)toB
    {
        NSLog(@"数据包:%@", [NSThread currentThread]);
    
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:kTimeOut];
    
        // 指定请求中所要GET的字节范围
        NSString *range = [NSString stringWithFormat:@"Bytes=%lld-%lld", fromB, toB];
        [request setValue:range forHTTPHeaderField:@"Range"];
        NSLog(@"range----%@", range);
    
        NSURLResponse *response = nil;
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
    
        // 写入文件,覆盖文件不会追加
    //    [data writeToFile:@"/Users/aplle/Desktop/1.png" atomically:YES];
        [self appendData:data];
    
        NSLog(@"response*******%@", response);
    }
    
    #pragma mark - 读取本地缓存文件大小
    - (long long)localFileSize
    {
        // 读取本地文件信息
        NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.cacheFile error:NULL];
        NSLog(@"读取本地文件信息%lld", [dict[NSFileSize] longLongValue]);
    
        return [dict[NSFileSize] longLongValue];
    }
    
    #pragma mark - 追加数据到文件
    - (void)appendData:(NSData *)data
    {
        // 推断文件是否存在
        NSFileHandle *fp = [NSFileHandle fileHandleForWritingAtPath:self.cacheFile];
        // 假设文件不存在创建文件
        if (!fp) {
            [data writeToFile:self.cacheFile atomically:YES];
        } else {
            // 假设文件已经存在追加文件
            // 1> 移动到文件末尾
            [fp seekToEndOfFile];
            // 2> 追加数据
            [fp writeData:data];
            // 3> 写入文件
            [fp closeFile];
        }
    }
    
    #pragma mark - 获取网络文件大小
    - (long long)fileSizeWithURL:(NSURL *)url
    {
        // 默认是GET
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:kTimeOut];
    
        // HEAD 头,仅仅是返回文件资源的信息,不返回详细是数据
        // 假设要获取资源的MIMEType,也必须用HEAD,否则,数据会被反复下载两次
        request.HTTPMethod = @"HEAD";
    
        // 使用同步方法获取文件大小
        NSURLResponse *response = nil;
    
        [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
    
        // expectedContentLength文件在网络上的大小
        NSLog(@"%lld", response.expectedContentLength);    
        return response.expectedContentLength;
    }
    @end

    使用工具类进行下载文件

    #import "MJViewController.h"
    #import "FileDownload.h"
    
    @interface MJViewController ()
    @property (nonatomic, strong) FileDownload *download;
    @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    @end
    
    @implementation MJViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        self.download = [[FileDownload alloc] init];
        // http://image.zcool.com.cn/56/13/1308200901454.jpg
        [self.download downloadFileWithURL:[NSURL URLWithString:@"http://image.zcool.com.cn/56/13/1308200901454.jpg"] completion:^(UIImage *image) {
    
            self.imageView.image = image;
        }];
    }
    
    @end
    
  • 相关阅读:
    重链剖分的总结与模板
    PBDS学习笔记(一)
    LCT 第一题 洛谷模板
    2018年暑假第四次周赛-图论部分题解
    后缀数组求不同子串的个数
    Codeforces Round #106 (Div. 2) Coloring Brackets(区间DP)
    Codeforces Round #510 (Div. 2) D. Petya and Array (权值线段树)
    HDU 3974 Assign the task (dfs序+线段树)
    Manthan, Codefest 18 (rated, Div. 1 + Div. 2) D.Valid BFS? (模拟)
    POJ
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/7226307.html
Copyright © 2011-2022 走看看