网络下载
下载的思路就是,数据请求一点就写入文件,这里需要用到文件类
- 当开始接收到数据的时候,创建一个空的文件夹
// 缓存文件夹
NSString * caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// 文件路径
NSString * file = [caches stringByAppendingPathComponent:@"text.mp4"];
// 创建一个空的文件
[[NSFileManager defaultManager] createFileAtPath:file contents:nil attributes:nil];
- 当接收到数据后,马上把数据写入到一开始创建好的文件
// 缓存文件夹
NSString * caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// 文件路径
NSString * file = [caches stringByAppendingPathComponent:@"text.mp4"];
// 创建一个句柄对象,可以操作数据,这里是写入
NSFileHandle * handle = [NSFileHandle fileHandleForWritingAtPath:file];
// 指定数据的写入位置,文件位置的最后面
[handle seekToEndOfFile];
// 写入数据
[handle writeData:data];
- 当数据接收完成之后需要关闭handle
// 当数据接收完毕之后,需要关闭handle
[handle closeFile];
// 这里一般为全局变量,所以没用需要置空
self.handle = nil
使用事例
#import "ViewController.h"
@interface ViewController ()<NSURLConnectionDataDelegate>
/** 句柄文件 */
@property (nonatomic,strong) NSFileHandle * handle;
/** 数据长度 */
@property (nonatomic,assign) NSInteger currentLength;
/** 文件的总大小长度 */
@property (nonatomic,assign) NSInteger contentLength;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSURL * url = [NSURL URLWithString:@""];
NSURLRequest * request = [NSURLRequest requestWithURL:url];
[NSURLConnection connectionWithRequest:request delegate:self];
}
#pragma mark - NSURLConnectionDataDelegate
/**
* 接收到响应的时候,创建一个空的文件夹
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response {
// 获取文件的总长度大小这里需要打印看response中具体返回了什么数据
self.contentLength = [response.allHeaderFields[@"Content-Length"] integerValue];
// 缓存文件夹
NSString * caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// 文件路径
NSString * file = [caches stringByAppendingPathComponent:@"text.mp4"];
// 创建一个空的文件
[[NSFileManager defaultManager] createFileAtPath:file contents:nil attributes:nil];
// 创建文件句柄
self.handle = [NSFileHandle fileHandleForWritingAtPath:file];
}
/**
* 接收到具体数据:马上把数据写入到一开始创建好的文件中
*/
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// 指定数据的写入位置 - 文件内容的最后面
[self.handle seekToEndOfFile];
// 写入数据
[self.handle writeData:data];
// 拼接总长度
self.currentLength += data.length;
// 进度
CGFloat progerss = 1.0 * self.currentLength / self.contentLength;
}
/**
* 当数据传输完毕的时候调用
*/
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// 关闭文件句柄
[self.handle closeFile];
self.handle = nil;
}
@end
大文件下载
程序在运行中的断点下载
// 文件的存放路径(caches)
#define JXMp4File [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"test.mp4"]
#import "ViewController.h"
@interface ViewController () <NSURLSessionDataDelegate>
/** 下载任务 */
@property (nonatomic, strong) NSURLSessionDataTask *task;
/** session */
@property (nonatomic, strong) NSURLSession *session;
/** 写文件的流对象 */
@property (nonatomic, strong) NSOutputStream *stream;
/** 文件的总长度 */
@property (nonatomic, assign) NSInteger contentLength;
@end
@implementation ViewController
- (NSURLSession *)session
{
if (!_session) {
_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
}
return _session;
}
- (NSOutputStream *)stream
{
if (!_stream) {
_stream = [NSOutputStream outputStreamToFileAtPath:JXMp4File append:YES];
}
return _stream;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"%@", XMGMp4File);
[[NSFileManager defaultManager] removeItemAtPath:XMGMp4File error:nil];
}
/**
* 开始下载
*/
- (IBAction)start:(id)sender {
// 创建一个Data任务
self.task = [self.session dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"]];
// 启动任务
[self.task resume];
}
/**
* 暂停下载
*/
- (IBAction)pause:(id)sender {
[self.task suspend];
}
/**
* 继续下载
*/
- (IBAction)goOn:(id)sender {
[self.task resume];
}
#pragma mark - <NSURLSessionDataDelegate>
/**
* 1.接收到响应
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
// 打开流
[self.stream open];
// 获得文件的总长度
self.contentLength = [response.allHeaderFields[@"Content-Length"] integerValue];
// 接收这个请求,允许接收服务器的数据
completionHandler(NSURLSessionResponseAllow);
}
/**
* 2.接收到服务器返回的数据(这个方法可能会被调用N次)
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
// 写入数据
[self.stream write:data.bytes maxLength:data.length];
// 目前的下载长度
// 获得某个文件的属性,NSFileSize为字典个中的值
NSInteger downloadLength = [[[NSFileManager defaultManager] attributesOfItemAtPath:JXMp4File error:nil][NSFileSize] integerValue];
// 下载进度
NSLog(@"%f", 1.0 * downloadLength / self.contentLength);
}
/**
* 3.请求完毕(成功\失败)
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
// 关闭流
[self.stream close];
self.stream = nil;
}
@end
大文件下载-断点下载
// 所需要下载的文件的URL
#define JXFileURL @"http://120.25.226.186:32812/resources/videos/minion_01.mp4"
// 文件名(沙盒中的文件名)
#define JXFilename JXFileURL.md5String
// 文件的存放路径(caches)
#define JXFileFullpath [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:JXFilename]
// 存储文件总长度的文件路径(caches)
#define JXTotalLengthFullpath [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"totalLength.JX"]
// 文件的已下载长度
#define JXDownloadLength [[[NSFileManager defaultManager] attributesOfItemAtPath:JXFileFullpath error:nil][NSFileSize] integerValue]
#import "ViewController.h"
#import "NSString+Hash.h"
#import "UIImageView+WebCache.h"
@interface ViewController () <NSURLSessionDataDelegate>
/** 下载任务 */
@property (nonatomic, strong) NSURLSessionDataTask *task;
/** session */
@property (nonatomic, strong) NSURLSession *session;
/** 写文件的流对象 */
@property (nonatomic, strong) NSOutputStream *stream;
/** 文件的总长度 */
@property (nonatomic, assign) NSInteger totalLength;
@end
@implementation ViewController
- (NSURLSession *)session
{
if (!_session) {
_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
}
return _session;
}
- (NSOutputStream *)stream
{
if (!_stream) {
_stream = [NSOutputStream outputStreamToFileAtPath:JXFileFullpath append:YES];
}
return _stream;
}
- (NSURLSessionDataTask *)task
{
if (!_task) {
NSInteger totalLength = [[NSDictionary dictionaryWithContentsOfFile:JXTotalLengthFullpath][JXFilename] integerValue];
if (totalLength && JXDownloadLength == totalLength) {
NSLog(@"----文件已经下载过了");
return nil;
}
// 创建请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"]];
// 设置请求头
// Range : bytes=xxx-xxx
NSString *range = [NSString stringWithFormat:@"bytes=%zd-", JXDownloadLength];
[request setValue:range forHTTPHeaderField:@"Range"];
// 创建一个Data任务
_task = [self.session dataTaskWithRequest:request];
}
return _task;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"%@", JXFileFullpath);
}
/**
* 开始下载
*/
- (IBAction)start:(id)sender {
// 启动任务
[self.task resume];
}
/**
* 暂停下载
*/
- (IBAction)pause:(id)sender {
[self.task suspend];
}
#pragma mark - <NSURLSessionDataDelegate>
/**
* 1.接收到响应
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
// 打开流
[self.stream open];
// 获得服务器这次请求 返回数据的总长度
self.totalLength = [response.allHeaderFields[@"Content-Length"] integerValue] + JXDownloadLength;
// 存储总长度
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:JXTotalLengthFullpath];
if (dict == nil) dict = [NSMutableDictionary dictionary];
dict[JXFilename] = @(self.totalLength);
[dict writeToFile:JXTotalLengthFullpath atomically:YES];
// 接收这个请求,允许接收服务器的数据
completionHandler(NSURLSessionResponseAllow);
}
/**
* 2.接收到服务器返回的数据(这个方法可能会被调用N次)
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
// 写入数据
[self.stream write:data.bytes maxLength:data.length];
// 下载进度
NSLog(@"%f", 1.0 * JXDownloadLength / self.totalLength);
}
/**
* 3.请求完毕(成功\失败)
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
// 关闭流
[self.stream close];
self.stream = nil;
// 清除任务
self.task = nil;
}
@end