ios-day23-01(ios开发之文件下载)

//
//  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

   
   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值