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
时间: 2024-10-09 22:12:27

iOS 文件下载的相关文章

iOS 文件下载 (AFNetwork 三方框架 文件名中文字符乱码问题解决)四

很久以前,就把这篇文章的andriod部分和服务器部分搞定,最近论文送审途中,于是写了几行简单的代码如下. 把AFNetwork拿来做一下.具体代码如下: -(void)download { NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; AFURLSessionManager *manager = [[AFURLSessionManager alloc] i

iOS 文件下载 (AFNetwork 三方框架 含progressView)五

1.创建request - (void)download2 { NSString *urlString = @"http:192.168.0.179:8080/Myweb/download.do"; urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSLog(@"hello"); NSURL *url = [NSURL URLWithStr

IOS文件下载

NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,  NSUserDomainMask,YES);//使用C函数NSSearchPathForDirectoriesInDomains来获得沙盒中目录的全路径. //  ***  NSString * documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocum

iOS开发 -文件下载(4 暂停和恢复)

iOS开发网络篇—文件下载(四·暂停和恢复) 一.Range简单说明 通过设置请求头Range可以指定每次从网路下载数据包的大小 Range示例 bytes=0-499 从0到499的头500个字节 bytes=500-999 从500到999的第二个500字节 bytes=500- 从500字节以后的所有字节 bytes=-500 最后500个字节 bytes=500-599,800-899 同时指定几个范围 Range小结 - 用于分隔 前面的数字表示起始字节数 后面的数组表示截止字节数,没

iOS开发 -文件下载(6压缩和解压)

iOS开发网络篇—文件下载(六·压缩和解压) 一.完成文件下载 需求:完成文件下载 1.在本地服务器中,添加一个图片的压缩文件. 2.代码示例: 文件下载器代码: 头文件 1 // 2 // YYfileDownloader.h 3 // 01-文件的下载(不合理) 4 // 5 // Created by apple on 14-7-1. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <Founda

iOS开发之网络编程--使用NSURLConnection实现大文件下载

主要思路(实现下载数据分段写入缓存中) 1.使用NSURLConnectionDataDelegate以及代理方法.2.在成功获取响应的代理方法中,获得沙盒全路径,并在该路径下创建空文件和文件句柄.3.在获取data的代理方法中,先设置句柄在沙盒全路径文件末尾,然后通过句柄写入data数据.4.在文件下载完的代理方法中,关闭句柄同时设置句柄引用为nil释放句柄和指针. 使用句柄的思路图(红色的箭头表示句柄,灰色的箭头表示移动的路径): 代码关键词: 类:NSFileHandle的方法 1.fil

iOS开发 -文件下载(5 下载功能的封装)

iOS开发网络篇—文件下载(五·下载功能的封装) 一.简单说明 在前面几篇文章介绍下载代码的基础上,此文分析对下载功能进行封装. 通过之前的代码,我们发现仅仅是下载一个文件就需要写很长的代码,那么如果要下载多个文件,就需要写多份代码.在这里,我们把下载一个文件的代码进行封装.控制器只需要知道,下载哪个文件,下载到哪个路径就可以了. 在对下载的功能进行封装后,添加一个文件下载器,一个文件下载器只下载一个文件,封装后如果要下载多个文件的话,那么只需要创建多个文件下载器对象就可以进行控制和下载了. 二

iOS开发 -文件下载(1不合理)

iOS开发网络篇—文件下载(一·不合理) 一.小文件下载 如果文件比较小,下载方式会比较多 直接用NSData的+ (id)dataWithContentsOfURL:(NSURL *)url; 利?NSURLConnection发送一个HTTP请求去下载 如果是下载图片,还可以利用SDWebImage框架 二.沙盒 1.在finder中,系统的一些文件(资源库)是隐藏的,可以通过在终端运行下图的代码,显示隐藏的文件. 显示隐藏系统文件: defaults write com.apple.fin

iOS开发 -文件下载(2合理)

iOS开发网络篇—文件下载(二·合理) 一.边下载,边写入 1.思路 把下载的data追加到文件的尾部,直到所有的数据下载完为止. 1.在连通了服务器的时候,创建一个空的文件到沙盒中NSFileManager(文件管理类) 2.创建写数据的文件句柄 3.在接收到服务器返回的数据后,把data写入到创建的空文件中,但是不能使用writeTofile(会覆盖) 3.1移动到文件的尾部 3.2从当前移动的位置,写入数据 4.服务器的数据加载完毕后关闭连接,不再输入数据在文件中 二.代码示例 1 //