使用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. Binder Native 层(二)

    Binder 框架及 Native 层 Binder机制使本地对象可以像操作当前对象一样调用远程对象,可以使不同的进程间互相通信.Binder 使用 Client/Server 架构,客户端通过服务端 ...

  2. sencha touch overlay 里使用 list

    1 sencha touch 中 list 如果不设置一个固定高度或 flex : 1,  list 的内容就不会显示出来. 主要是因为 list 是可滚动的,你不设置高度 ,list 的高度默认就是 ...

  3. IBM Worklight OutOfMemoryError: Java heap space 错误

    在启动  IBM Worklight 6.0 server 的时候,报了一个  OutOfMemory 的错误: [INFO    ] FWLSE4006I: Worklight Studio is ...

  4. 使用BeanUtils封装数据时数据类型的转换

    //获得表单数据 Map<String, String[]> properties = request.getParameterMap(); User user = new User(); ...

  5. Android文字识别之tesseract的使用

    关于tesseract识别工具有Google提供的版本有tesseract-android-tools,不过还有一个tesseract-two也是非常好用的,这里我们使用的是tesseract-two ...

  6. ubuntu 64上的GCC如何编译32位程序

    运行命令 gcc -v 显示: Target: x86_64-linux-gnu 所以,我这里的gcc默认生成64位的程序. 如果想编出32位的程序,就要加 -m32选项.可是我尝试了,还是不行. 原 ...

  7. Linux中让普通用户拥有超级用户的权限

    问题 假设用户名为:ali 如果用户名没有超级用户权限,当输入 sudo + 命令 时, 系统提示: ali is not in the sudoers file.  This incident wi ...

  8. 从 JDK 源码角度看 Object

    Java的Object是所有其他类的父类,从继承的层次来看它就是最顶层根,所以它也是唯一一个没有父类的类.它包含了对象常用的一些方法,比如getClass.hashCode.equals.clone. ...

  9. mongodb操作之mongoose

    /** * Created by chaozhou on 2015/10/6. */ var mongoose = require("mongoose"); var db = mo ...

  10. 简述Spring及配置

    简述Spring及配置 Spring最主要的思想就是IoC(Inversionof Control,控制反转),或者成为DI(Dependency Injection,依赖注入) 一.springMV ...