使用NSURLConnection实现大文件断点下载

由于是实现大文件的断点下载,不是下载一般图片什么的.在设计这个类的时候本身就不会考虑把下载的文件缓存到内存中,而是直接写到文件系统.

要实现断点下载,需要满足1个条件,那就是,必须要服务器支持断点下载.

实现的思路是这样子的:

1.  第一次会获取到被下载文件的总大小(服务器提供这个值)

  下载文件总大小 = 期望从服务器获取文件的大小 + 本地已经下载的文件的大小

2.  设置请求的缓存策略为不会读取本地中已经缓存的数据(NSURLRequestReloadIgnoringLocalCacheData)

3.  在去服务器请求数据之前先获取到本地已经下载好的部分文件的长度,以这个参数设置进Range中到服务器去请求剩下的数据

4.  当从网络获取到一定的数据的时候,我们直接将数据写进文件系统中

YXDownloadNetwork.h

//
// YXDownloadNetwork.h
// Download
//
// http://home.cnblogs.com/u/YouXianMing/
//
// Copyright (c) 2014年 Y.X. All rights reserved.
// #import <Foundation/Foundation.h> // block的相关定义
typedef void (^downloadProgress_t)(long long currentBytes, long long totalBytes);
typedef void (^completion_t)(NSDictionary *headers, NSData *body); @interface YXDownloadNetwork : NSObject // 将block定义成属性
@property (nonatomic, copy) downloadProgress_t downloadProgress;
@property (nonatomic, copy) completion_t completion; // 初始化方法
- (instancetype)initWithUrlString:(NSString *)urlString cacheCapacity:(unsigned long long)capacity;
- (void)start; @end

YXDownloadNetwork.m

//
// YXDownloadNetwork.m
// Download
//
// http://home.cnblogs.com/u/YouXianMing/
//
// Copyright (c) 2014年 Y.X. All rights reserved.
// #import "YXDownloadNetwork.h" @interface YXDownloadNetwork ()<NSURLConnectionDelegate, NSURLConnectionDataDelegate> @property (nonatomic, assign) unsigned long long totalLength; // 文件总大小
@property (nonatomic, assign) unsigned long long startDataLength; // 本地存在文件的大小
@property (nonatomic, assign) unsigned long long expectedLength; // 从服务器期望文件的大小
@property (nonatomic, assign) unsigned long long cacheCapacity; // 缓存文件容量,以k为单位 @property (nonatomic, strong) NSURLConnection *dataConncetion; // 网络连接
@property (nonatomic, strong) NSDictionary *responseHeaders; // 网络连接头部信息
@property (nonatomic, strong) NSFileHandle *file; // 文件操作句柄
@property (nonatomic, strong) NSMutableData *cacheData; // 用于缓存的data数据 @end @implementation YXDownloadNetwork - (instancetype)initWithUrlString:(NSString *)urlString cacheCapacity:(unsigned long long)capacity
{
self = [super init]; if (self)
{
// 获取缓存容量
if (capacity <= )
{
_cacheCapacity = * ;
}
else
{
_cacheCapacity = capacity * ;
} // 获取用于缓存的数据
_cacheData = [NSMutableData new]; // 获取文件名以及文件路径
NSString *fileName = [urlString lastPathComponent];
NSString *filePath = \
fileFromPath([NSString stringWithFormat:@"/Documents/%@", fileName]); // 记录文件起始位置
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
// 从文件中读取出已经下载好的文件的长度
_startDataLength = [[NSData dataWithContentsOfFile:filePath] length];
}
else
{
// 不存在则创建文件
_startDataLength = ;
[[NSFileManager defaultManager] createFileAtPath:filePath
contents:nil
attributes:nil];
} // 打开写文件流
_file = [NSFileHandle fileHandleForWritingAtPath:filePath]; // 创建一个网络请求
NSMutableURLRequest* request = \
[NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]]; // 禁止读取本地缓存
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; // 设置断点续传(需要服务器支持)
[request setValue:[NSString stringWithFormat:@"bytes=%llu-", _startDataLength]
forHTTPHeaderField:@"Range"]; // 开始创建连接
self.dataConncetion = \
[[NSURLConnection alloc] initWithRequest:request
delegate:self
startImmediately:NO];
} return self;
} - (void)start
{
[self.dataConncetion start];
} - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if([response isKindOfClass:[NSHTTPURLResponse class]])
{
NSHTTPURLResponse *r = (NSHTTPURLResponse *)response; // 如果能获取到期望的数据长度就执行括号中的方法
if ([r expectedContentLength] != NSURLResponseUnknownLength)
{
// 获取剩余要下载的
_expectedLength = [r expectedContentLength]; // 计算出总共需要下载的
_totalLength = _expectedLength + _startDataLength; // 获取头文件
_responseHeaders = [r allHeaderFields];
}
else
{
NSLog(@"不支持断点下载");
}
}
} - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData
{
// 追加缓存数据
[_cacheData appendData:theData]; // 如果该缓存数据的大小超过了指定的缓存大小
if ([_cacheData length] >= _cacheCapacity)
{
// 移动到文件结尾
[_file seekToEndOfFile]; // 在文件末尾处追加数据
[_file writeData:_cacheData]; // 清空缓存数据
[_cacheData setLength:];
} // 当前已经下载的所有数据的总量
_startDataLength += [theData length]; // 如果指定了block
if (_downloadProgress)
{
_downloadProgress(_startDataLength, _totalLength);
}
} - (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 移动到文件结尾
[_file seekToEndOfFile]; // 在文件末尾处追加最后的一点缓存数据
[_file writeData:_cacheData]; // 清空缓存
[_cacheData setLength:]; NSLog(@"下载完成哦");
} NS_INLINE NSString * fileFromPath(NSString *filePath)
{
return [NSHomeDirectory() stringByAppendingString:filePath];
} @end

测试代码如下:

实际上这个类还有很多地方不完善,但至少能起到抛砖引玉的作用,它更牛逼的用途靠你来修改了,亲.

使用NSURLConnection实现大文件断点下载的更多相关文章

  1. ios开发网络学习四:NSURLConnection大文件断点下载

    #import "ViewController.h" @interface ViewController ()<NSURLConnectionDataDelegate> ...

  2. iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载+使用输出流代替文件句柄

    前言:本篇讲解,在前篇iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载的基础上,使用输出流代替文件句柄实现大文件断点续传.    在实际开发中,输入输出流用的比较少,但 ...

  3. iOS 大文件断点下载

    iOS 在下载大文件的时候,可能会因为网络或者人为等原因,使得下载中断,那么如何能够进行断点下载呢? // resumeData的文件路径 #define XMGResumeDataFile [[NS ...

  4. Retrofit 2.0 超能实践(四),完成大文件断点下载

    作者:码小白 文/CSDN 博客 本文出自:http://blog.csdn.net/sk719887916/article/details/51988507 码小白 通过前几篇系统的介绍和综合运用, ...

  5. iOS- 利用AFNetworking(AFN) - 实现文件断点下载

    https://www.cnblogs.com/qingche/p/3500746.html 1. 定义一个全局的AFHttpClient:包含有 1> baseURL 2> 请求 3&g ...

  6. php实现大文件断点续传下载实例

    php实现大文件断点续传下载实例,看完你就知道超过100M以上的大文件如何断点传输了,这个功能还是比较经典实用的,毕竟大文件上传功能经常用得到. require_once('download.clas ...

  7. iOS- 利用AFNetworking3.0+(最新AFN) - 实现文件断点下载

    官方建议AFN的使用方法   0.导入框架准备工作 •1. 将AFNetworking3.0+框架程序拖拽进项目   •2. 或使用Cocopod 导入AFNetworking3.0+   •3.   ...

  8. iOS-服务器文件断点下载

    文件下载基本步骤:1.获取下载链接,创建响应发送请求.(使用异步请求,避免因文件过大下载时间长而阻塞主线程).2.当接到响应时在下载目录中创建文件.创建文件使用NSFileHandle进行文件内部处理 ...

  9. android网络编程之HttpUrlConnection的讲解--实现文件断点下载

    1.没有实现服务器端,下载地址为网上的一个下载链接. 2.网络开发不要忘记在配置文件中添加访问网络的权限 <uses-permission android:name="android. ...

随机推荐

  1. 解决执行maven项目出现 SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”. error

    最近再弄maven项目,运行起来没有问题,但是Console控制台会报错,比如说如下的问题异常提示: 由此我们可以看出,报出错误的地方主要是slf4j的jar包,而故障码中“Failed to loa ...

  2. unity3d vscode

    原来unity3d里assets store有一个插件,下载就行了,插件名就叫vscode 下载完了之后,preference里就会出现,vscode,Enable Integration 这一项勾上 ...

  3. (转)如何使用Journalctl查看并操作Systemd日志

    原文:https://blog.csdn.net/zstack_org/article/details/56274966 内容简介 作为最具吸引力的优势,systemd拥有强大的处理与系统日志记录功能 ...

  4. (转)shell变量及扩展

    1.shell变量 shell变量赋值语句为”name=[value]“,等号两边不能有空格,可以给shell变量追加内容”name+=value“,取消shell变量的设置使用”unset name ...

  5. Bash编程(4) 参数与变量

    1. 变量命名 变量命名只能使用数字.下划线.字母,且仅能以下划线或字母开头. 变量很少使用单个字母,单个字母一般用于循环或读取一次性文件的时候. 例: while IFS=: read login ...

  6. Hadoop科普文—常见的45个问题解答

    1.Hadoop集群可以运行的3个模式? 单机(本地)模式 伪分布式模式 全分布式模式 2.  单机(本地)模式中的注意点? 在单机模式(standalone)中不会存在守护进程,所有东西都运行在一个 ...

  7. 利用Map解决复杂业务

    遍历出题库表的题库名称和题库id,根据题目id即questionBankId获取 分组,即该题库题目总数,该题库题目正确数,该题库已回答题目数. <sqltemplate id="co ...

  8. Restful的理解,Restful 优缺点

    写一下我对restful的理解,最近换工作面试的时候有问到我restful api的东西,工作中以前很多项目也是webapi + js前台控件的形式构建系统.实际上感觉restful太“理想化”,用起 ...

  9. 44个 Javascript 变态题解析

    原题来自: http://javascript-puzzlers.herokuapp.com/ 读者可以先去做一下感受感受. 当初笔者的成绩是 21/44... 当初笔者做这套题的时候不仅怀疑智商, ...

  10. [转]Asp.Net Web API 2第十七课——Creating an OData Endpoint in ASP.NET Web API 2(OData终结点)

    本文转自:http://www.cnblogs.com/aehyok/p/3545824.html 前言 很久没更新博客了,加上刚过年,现在准备重新开战,继续自己的学习之路.本文已同步到Web API ...