使用NSURLConnection实现大文件断点下载
使用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实现大文件断点下载的更多相关文章
- ios开发网络学习四:NSURLConnection大文件断点下载
#import "ViewController.h" @interface ViewController ()<NSURLConnectionDataDelegate> ...
- iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载+使用输出流代替文件句柄
前言:本篇讲解,在前篇iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载的基础上,使用输出流代替文件句柄实现大文件断点续传. 在实际开发中,输入输出流用的比较少,但 ...
- iOS 大文件断点下载
iOS 在下载大文件的时候,可能会因为网络或者人为等原因,使得下载中断,那么如何能够进行断点下载呢? // resumeData的文件路径 #define XMGResumeDataFile [[NS ...
- Retrofit 2.0 超能实践(四),完成大文件断点下载
作者:码小白 文/CSDN 博客 本文出自:http://blog.csdn.net/sk719887916/article/details/51988507 码小白 通过前几篇系统的介绍和综合运用, ...
- iOS- 利用AFNetworking(AFN) - 实现文件断点下载
https://www.cnblogs.com/qingche/p/3500746.html 1. 定义一个全局的AFHttpClient:包含有 1> baseURL 2> 请求 3&g ...
- php实现大文件断点续传下载实例
php实现大文件断点续传下载实例,看完你就知道超过100M以上的大文件如何断点传输了,这个功能还是比较经典实用的,毕竟大文件上传功能经常用得到. require_once('download.clas ...
- iOS- 利用AFNetworking3.0+(最新AFN) - 实现文件断点下载
官方建议AFN的使用方法 0.导入框架准备工作 •1. 将AFNetworking3.0+框架程序拖拽进项目 •2. 或使用Cocopod 导入AFNetworking3.0+ •3. ...
- iOS-服务器文件断点下载
文件下载基本步骤:1.获取下载链接,创建响应发送请求.(使用异步请求,避免因文件过大下载时间长而阻塞主线程).2.当接到响应时在下载目录中创建文件.创建文件使用NSFileHandle进行文件内部处理 ...
- android网络编程之HttpUrlConnection的讲解--实现文件断点下载
1.没有实现服务器端,下载地址为网上的一个下载链接. 2.网络开发不要忘记在配置文件中添加访问网络的权限 <uses-permission android:name="android. ...
随机推荐
- Java - 冒泡排序的基础算法(尚学堂第七章数组)
/** * 冒泡排序的基础算法 */ import java.util.Arrays; public class TestBubbleSort1 { public static void main(S ...
- 003-BootStrap完整模板
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8& ...
- JBoss7.1.1远程无法访问
一般情况下在JBoss7.1.1.Final版本中配置standalone/configuration/standalone.xml<interfaces>里面name为public的&l ...
- 这是关于FastJson的一个使用Demo,在Java环境下验证的
public class User { private int id; private String name; public int getId() { return id; } public vo ...
- 面试题目: 获取服务器IP和客户端IP
[面试题目] 怎么获取服务器IP和客户端IP地址? I. PHP获取客户端IP, 可通过下面系统变量 1. $_SERVER['Remote_Addr'] 2. $_SERVER['HTTP_CLIE ...
- Wordpress 忘记密码怎么办?
最近一段时间很忙,很久没更新自己博客了,结果忘记了密码? 这里提供两种方法解决. 1. 点击忘记密码,会根据你的邮箱发送一封密码重置邮件,如果没配制邮件或是空间没开启支持,那就有点悲剧了,可以用第二 ...
- python3根据地址批量获取百度地图经纬度
python3代码如下: import requests import time def get_mercator(addr): url= 'http://api.map.baidu.com/geoc ...
- Java入门系列-25-NIO(实现非阻塞网络通信)
还记得之前介绍NIO时对比传统IO的一大特点吗?就是NIO是非阻塞式的,这篇文章带大家来看一下非阻塞的网络操作. 补充:以数组的形式使用缓冲区 package testnio; import java ...
- WeUI logo专为微信设计的 UI 库 WeUI
http://www.oschina.net/p/weui?fromerr=FnwHyWAb http://weui.github.io/weui/
- shell脚本检测监控mysql的CPU占用率
网站访问量大的时候mysql的压力就比较大,当mysql的CPU利用率超过300%的时候就不能提供服务了,近乎卡死状态,这时候最好的方法 就是重启mysql服务.由于这种事具有不可预见性,我们不知道什 ...