使用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. Jmeter基础元件

    测试计划 1.Test Plan (测试计划) 用来描述一个性能测试,包含与本次性能测试所有相关的功能.也就说JMeter创建性能测试的所有内容是于基于一个计划的. 下面看看一个计划下面都有哪些功能模 ...

  2. 进入保护模式(三)——《x86汇编语言:从实模式到保护模式》读书笔记17

    (十)保护模式下的栈 ;以下用简单的示例来帮助阐述32位保护模式下的堆栈操作 mov cx,00000000000_11_000B ;加载堆栈段选择子 mov ss,cx mov esp,0x7c00 ...

  3. Oracle 12c心得

    1.重新启动Listener后,远程客户端登录不了,只能全新启动Oralce服务才能正常,经分析,用Net Manager增加一个服务器的IP地址的监听. 执行 net start 监听服务名 再远程 ...

  4. org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'xxxx' is not present

    org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'xxx ...

  5. 架构实战项目心得(七):使用SpringBoot+Dubbo+Mybatisplus+Oracle搭建后台项目框架(二)

    接下来我们将整合mybatisplus+Oracle,实现一个简单的查询.(期间踩了很多坑,遇到一些问题,还好慢慢解决了.现在是通过配置文件的方式来进行dubbo服务的注册和发布,希望以后能在学习和实 ...

  6. linq——常用方法

    take  前几 skip   跳过前几 takeWhile   var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);  / ...

  7. SpringBoot 开启debug

    项目基于gradle ,今天想断点debug一下springboot,查阅资料后,纪录一下步骤. 创建Remote 创建gradle.properities 在当前项目下创建gradle.proper ...

  8. IDEA创建Maven项目和子模块

    一.新建Project a. 新建项目,点击Create New Project b. 选择使用maven来新建项目 选择新建Maven模块(对IDEA来说是项目) 如果Project SDK那里没有 ...

  9. webpack build后生成的app、vendor、manifest三者有何职能不同?

    贴一下之前vue脚手架的webpack3配置: app.js是入口js,vendor则是通过提取公共模块插件来提取的代码块(webpack本身带的模块化代码部分),而manifest则是在vendor ...

  10. svg基础知识体系建立

    一.简介:SVG 是使用 XML 来描述二维图形和绘图程序的语言. SVG 指可伸缩矢量图形 (Scalable Vector Graphics) SVG 用来定义用于网络的基于矢量的图形 SVG 使 ...