使用NSURLConnection实现大文件断点下载
2023-09-14 08:57:58 时间
使用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数据 @implementation YXDownloadNetwork - (instancetype)initWithUrlString:(NSString *)urlString cacheCapacity:(unsigned long long)capacity self = [super init]; if (self) // 获取缓存容量 if (capacity = 0) _cacheCapacity = 100 * 1024; else _cacheCapacity = capacity * 1024; // 获取用于缓存的数据 _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 = 0; [[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:0]; // 当前已经下载的所有数据的总量 _startDataLength += [theData length]; // 如果指定了block if (_downloadProgress) _downloadProgress(_startDataLength, _totalLength); - (void)connectionDidFinishLoading:(NSURLConnection *)connection // 移动到文件结尾 [_file seekToEndOfFile]; // 在文件末尾处追加最后的一点缓存数据 [_file writeData:_cacheData]; // 清空缓存 [_cacheData setLength:0]; NSLog(@"下载完成哦"); NS_INLINE NSString * fileFromPath(NSString *filePath) return [NSHomeDirectory() stringByAppendingString:filePath]; @end
测试代码如下:
实际上这个类还有很多地方不完善,但至少能起到抛砖引玉的作用,它更牛逼的用途靠你来修改了,亲.
C#多线程下载、断点续传的实现 做Unity热更功能的时候,发现单线程下载大尺寸资源文件的效率太低,专门去研究了下多线程下载,这里记录下相关知识点。
「Unity」基于UnityWebRequest的HTTP文件断点续传 此处需要手动开启协程未考虑网络文件变动的问题,需要的话可以自行进行md5比对若需要分片下载,可以通过修改Range相关值实现 using System;using System.Collections;using System.
iOS - NSURLConnection 网络请求 @interface NSURLConnection : NSObject class NSURLConnection : NSObject DEPRECATED: The NSURLConnection class should no longer be used. NSURLSession is the replacement for NSURLConnection 从 iOS 9 开始 NSURLConnection 的大部分方法被废弃。
相关文章
- PHP文件下载功能实现
- Windows VS2017 编译 libssh2 1.7.0(执行命令、文件上传、下载)
- iOS开发之网络编程--4、NSURLSessionDataTask实现文件下载(离线断点续传下载) <进度值显示优化>
- iOS开发之网络编程--3、NSURLSessionDataTask实现文件下载(离线断点续传下载)
- 关于SpingMVC实现文件下载你所不知道的
- Spring MVC 实现文件的上传和下载
- 使用C#调用旋风快车和迅雷下载文件 也是C#调用Com的好例子!
- C#实现文件下载的几种方式
- 利用SecureCRT上传、下载文件(使用sz与rz命令),超实用!
- python 下载.whl 文件,查看已安装软件包方法
- JS下载文件,解决文件直接在浏览器打开的情况
- 服务器端实现文件下载功能代码
- python实现下载文件路径自动添加(1)的递增路径
- 【问题解决方案】Xshell连接服务器并实现上传和下载文件
- 【转载】文件下载FileDownloader
- 使用springMVC实现文件上传和下载之文件下载
- 【SpringBoot笔记12】SpringBoot框架实现文件上传和文件下载
- 【SpringMVC笔记11】SpringMVC实现文件上传和下载
- 如何将文件从本机上传到docker容器或下载
- Spring Boot配置MinIO(实现文件上传、下载、删除)
- SpringBoot整合oss实现文件的上传,查看,删除,下载
- Http服务器实现文件上传与下载(一)
- Http服务器实现文件上传与下载(四)
- 【Android 逆向】修改 Android 的 apk 安装包内的文件并重新打包 ( apktool_2.6.0.jar 下载和使用 | zipalign 文件对齐 | apksigner 签名 )
- 面试官:如何用a标签实现文件下载?(一文带你手撕知识点)
- 前端必备技能知识:JS导出Blob流文件为Excel表格、Vue.js使用Blob的方式实现excel表格的下载(流文件下载)
- [springMVC学习]10、文件上传和下载
- Maven下载jar包时出错、Maven仓库中出现.lastUpdated结尾的文件问题及解决