使用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. (转)基于CentOS 7安装Zabbix 3.4和Zabbix4.0

    原文:https://blog.csdn.net/leshami/article/details/78708049 CentOS 7环境下Zabbix4.0的安装和配置实例-----------htt ...

  2. spring data jpa关联查询(一对一、一对多、多对多)

    在实际过往的项目中,常用的查询操作有:1.单表查询,2.一对一查询(主表和详情表)3.一对多查询(一张主表,多张子表)4.多对多查询(如权限控制,用户.角色多对多).做个总结,所以废话不多说. 使用i ...

  3. Python openpyxl Read

    #! /usr/bin/env python # coding=utf-8 from openpyxl import Workbook, load_workbook wb = load_workboo ...

  4. java获取当前秒数输出

    Date的getSeconds()已经过时了.不建议用.所以用了下面方法 Calendar c = Calendar.getInstance(); while(true) {            c ...

  5. HtmlUnit 开发网络爬虫

    网络爬虫第一个要面临的问题,就是如何抓取网页,抓取其实很容易,没你想的那么复杂,一个开源HtmlUnit包,几行代码就OK啦! 通常在一个页面中会包含别的Url,在别的Url当中又会包含更多的Url. ...

  6. 【百度之星2014~复赛 解题报告~正解】The Query on the Tree

    声明 笔者最近意外的发现 笔者的个人网站http://tiankonguse.com/ 的很多文章被其它网站转载,但是转载时未声明文章来源或参考自 http://tiankonguse.com/ 网站 ...

  7. awk常用命令总结

    awk工具,主要将一行分成“字段”来处理. awk '条件类型1{动作1} 条件类型2{动作2}...‘ filename awk主要是处理每一行的字段内的数据,而默认的字段的分隔符为空格键或[tab ...

  8. bzoj 5252: [2018多省省队联测]林克卡特树

    Description 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做& ...

  9. C#,动态加载DLL,通过反射,调用参数,方法,窗体

    .net中常会用到动态加载DLL,而DLL中可能包含各种参数.方法.窗体,如何来调用动态加载这些参数.方法.窗体呢? 在C#中,我们要使用反射,首先要搞清楚以下命名空间中几个类的关系: System. ...

  10. ubuntu基本配置学习(1)

    [转载]源自:http://www.haogongju.net/art/2048612 附加另外一篇文章:http://www.cnblogs.com/vincent-hv/archive/2013/ ...