大文件下载--断点续传--NSURLConnection

有了上一篇文章的铺垫直接上代码,下面是分析原理.

//  ViewController.m
//  大文件下载
//  Created by apple on 15/11/11.
//  Copyright © 2015年 LDSmallCat. All rights reserved.
#import "ViewController.h"
#import "DACircularProgressView.h"//进度条的第三方框架
@interface ViewController ()<NSURLConnectionDataDelegate>
//下载和暂停按钮
@property (weak, nonatomic) IBOutlet UIButton *button;
//用来写数据的文件句柄对象
@property(nonatomic,strong) NSFileHandle *writeHandle;
//文件的总大小.用已经下载的进度 除以 文件的总大小,做出进度条
@property(nonatomic,assign) long long totalLength;
//当前已经写入的文件大小.已经下载的,
@property(nonatomic,assign) long long currentLength;
///链接对象
@property (nonatomic, strong) NSURLConnection *conn;
//进度条
@property(nonatomic,weak) DACircularProgressView * circleView;
@end
@implementation ViewController
- (void)viewDidLoad{
    [super viewDidLoad];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    NSLog(@"didFailWithError");
}
//接收到响应就会调用
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    //下载完成后 再次点击的时候,如果为1就直接返回,不在下载,或弹框告诉用户已经存在,
    //需要将self.currentLength写入本地文件才能做到不会重复下载.就是说这个程序无法避免重复下载
    if (self.currentLength) return;
    //数据保存的路径
    NSString * caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString * filepath = [caches stringByAppendingPathComponent:@"download2.mp4"];
    //通过这个路径创建一个文件  到 沙盒中
    NSFileManager * mgr = [NSFileManager defaultManager];
    [mgr createFileAtPath:filepath contents:nil attributes:nil];
    //创建一个用来写入文件数据的文件句柄
    self.writeHandle = [NSFileHandle fileHandleForWritingAtPath:filepath];
    //获取文件总大小
    self.totalLength = response.expectedContentLength;
    NSLog(@"didReceiveResponse文件总大小%lld",self.totalLength);
}
//接受到数据就会调用,如果数据很大会被调用多次.边下边存储到沙盒,不会有内存问题
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    //移动到文件的最后面
    [self.writeHandle seekToEndOfFile];
    //数据写入沙盒
    [self.writeHandle writeData:data];
    //累计文件长度,通过循环不断增大这个值,在下面的方法中拿到这个值量化去下载任务
    //比如这里第一次拿到300字节,下面请求下载0-300的任务,下次拼接后为1000,下面请求下载300-1000
    //的任务,
    self.currentLength += data.length;
    self.circleView.progress = (double)self.currentLength / self.totalLength;
    //经过不断拼接,已经写入的数据,
    NSLog(@"didReceiveData   已经下载的数据%lld   ",self.currentLength);
}
//下载完成后调用,做些处理工作
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    //变量归零
    self.currentLength = 1;
    self.totalLength = 0;
    //关闭文佳
    [self.writeHandle closeFile];
    self.writeHandle = nil;
}
- (IBAction)downLoad:(UIButton *)sender{
    //状态取反
    sender.selected = ! sender.selected;
    //断点续传,断点下载
    if(sender.selected){
        //1.点击下载,创建URL,发送请求.url中不能有中文
        NSURL * url = [NSURL URLWithString:@"http://localhost/dawenjianyasuo.zip"];
        //2.请求
        NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
        self.currentLength = 0;
        //设置请求头.实现的要点在这里,此处的Rang属性实现了下载的控制,用self.currentLength
        //来保存已经下载了多少字节,
        NSString * range = [NSString stringWithFormat:@"bytes=%lld-",self.currentLength];
        [request setValue:range forHTTPHeaderField:@"Range"];
        //下载(创建完conn对象后,会自动发起一个异步请求)

self.conn = [NSURLConnection connectionWithRequest:request delegate:self]; }else{//一旦点击暂停创建的request就会销毁,再次点击下载时需要重新创建. [self.conn cancel]; self.conn = nil; } } @end

整体流程:

原理会在下一篇文章中说明,

 

posted @ 2015-11-11 22:06  LDSmallCat  阅读(243)  评论(0编辑  收藏  举报