//
// JLViewController.m
// 01-文件下载
//
// Created by Mac on 15-4-10.
// Copyright (c) 2015年 vxinyou. All rights reserved.
//
#import "JLViewController.h"
#import "JLFileDownload.h"
@interface JLViewController ()
- (IBAction)beginDownload;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation JLViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)beginDownload {
JLFileDownload *download = [[JLFileDownload alloc] init];
// 创建url
NSURL *url = [NSURL URLWithString:@"图片文件的路径"];
// 根据url下载文件,并处理下载完毕的文件
[download downloadFileWithURL:url completion:^(NSData *data) {
UIImage *image = [UIImage imageWithData:data];
self.imageView.image = image;
}];
}
@end
//
// JLFileDownload.h
// 01-文件下载
//
// Created by Mac on 15-4-10.
// Copyright (c) 2015年 vxinyou. All rights reserved.
//
#import
@interface JLFileDownload : NSObject
/**
* 根据一个url去服务器下载文件
*
* @param url 要下载文件的路径
* @param completion 下载完成后的处理
* @param data 文件数据
*/
- (void)downloadFileWithURL:(NSURL *)url completion:(void (^)(NSData *data))completion;
@end
//
// JLFileDownload.m
// 01-文件下载
//
// Created by Mac on 15-4-10.
// Copyright (c) 2015年 vxinyou. All rights reserved.
//
#import "JLFileDownload.h"
#import "NSString+Password.h"
// 每次下载的字节数(byte)
#define kBytesPerTimes 20480
@interface JLFileDownload()
// 下载的文件存储的路径
@property (nonatomic, strong)NSString *savePath;
@property (nonatomic, strong)NSData *data;
@end
@implementation JLFileDownload
- (void)downloadFileWithURL:(NSURL *)url completion:(void (^)(NSData *data))completion{
// 创建一个串行队列
dispatch_queue_t queue = dispatch_queue_create("com.download", DISPATCH_QUEUE_SERIAL);
// 异步执行下载任务
dispatch_async(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
// 把对url进行MD5加密之后的结果当成文件名
[self setSavePath:[url absoluteString]];
// self.savePath = [url absoluteString];
// 根据url计算出要下载的文件的大小
long long fileSize = [self fileSizeWithURL:url];
// 读取本地缓存文件的大小
long long cacheFileSize = [self localFileSize];
// 如果 要下载的文件的大小 跟 本地相同文件名文件的大小 相等
if (fileSize == cacheFileSize) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(self.data);
});
// 提示用户:文件已经存在
return;
}
// 每次要下载的是从 fromByte ~ toByte 的数据
long long fromByte = 0;
long long toByte = 0;
while (fileSize > kBytesPerTimes) {
// 如果一个文件的大小为1000byte,那么我们要下载的数据是0byte ~ 999byte
toByte = fromByte + kBytesPerTimes -1;
[self downloadDataWithURL:url fromByte:fromByte toByte:toByte];
fileSize -= kBytesPerTimes;
fromByte += kBytesPerTimes;
}
[self downloadDataWithURL:url fromByte:fromByte toByte:fromByte + fileSize -1];
dispatch_async(dispatch_get_main_queue(), ^{
completion(self.data);
});
});
}
#pragma mark -set和get方法
- (NSData *)data{
if (_data == nil) {
_data = [NSData dataWithContentsOfFile:self.savePath];
}
return _data;
}
- (void)setSavePath:(NSString *)fileName{
// 获取缓存目录(通过网络下载的文件都应该存到缓存目录中)
NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
// 为了保证文件名的唯一性
fileName = [fileName MD5];
// 拼接路径
_savePath = [cacheDir stringByAppendingPathComponent:fileName];
}
#pragma mark -下载指定字节范围的数据包
- (void)downloadDataWithURL:(NSURL *)url fromByte:(long long)fromByte toByte:(long long)toByte{
// cachePolicy:缓存策略 NSURLRequestReloadIgnoringCacheData:忽略本地的内存缓存
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0f];
request.HTTPMethod = @"GET";
// 指定请求中所要GET的字节范围
NSString *range = [NSString stringWithFormat:@"bytes=%lld-%lld", fromByte, toByte];
[request setValue:range forHTTPHeaderField:@"Range"];
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
NSLog(@"%@",response);
// 添加数据到文件
[self appendData:data];
}
#pragma mark -添加数据到文件
- (void)appendData:(NSData *)data{
// 判断文件是否存在
NSFileHandle *fp = [NSFileHandle fileHandleForWritingAtPath:self.savePath];
// 如果文件不存在,则创建文件
if (!fp) {
[data writeToFile:self.savePath atomically:YES];
} else {
// 如果文件已经存在:
// 1 指针移动到文件末尾
[fp seekToEndOfFile];
// 2 在文件末尾添加数据
[fp writeData:data];
// 3 写入文件
[fp closeFile];
}
}
#pragma mark -读取本地缓存文件的大小
- (long long)localFileSize{
// 读取本地文件的信息(这样做的目的是:如果要下载的文件已经缓存在本地,无需下载)
NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.savePath error:NULL];
// 返回文件大小(单位:byte)
return [dict[NSFileSize] longLongValue];
}
#pragma mark -根据url计算出要下载的文件的大小
- (long long)fileSizeWithURL:(NSURL *)url{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:10.0f];
// 默认是GET请求
// 如果是HEAD请求,返回的只是文件的描述信息,不返回文件本身数据
// 如果要获取资源的MIMEType,也必须用HEAD请求,否则数据会被重复下载
request.HTTPMethod = @"HEAD";
NSURLResponse *response = nil;
// 发送同步请求,不要用异步请求,因为这已经是子线程。
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
// NSLog(@"文件总大小:%lld", response.expectedContentLength);
// 返回文件大小(单位:byte)
return response.expectedContentLength;
}
@end