小文件下载
NSURLConnection下载小文件
#import "ViewController.h"
@interface ViewController ()<NSURLConnectionDataDelegate>
/** 记录文件的总大小 */
@property (nonatomic, assign) long long totalSize;
/** 下载的文件名 */
@property (nonatomic, strong) NSString *fileName;
/** 已经下载的data */
@property (nonatomic, strong) NSMutableData *downLoadData;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_04.mp4"];
NSURLRequest *rquest = [NSURLRequest requestWithURL:url];
// 发送请求
[NSURLConnection connectionWithRequest:rquest delegate:self];
}
#pragma mark - NSURLConnectionDataDelegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSHTTPURLResponse *httpRespone = (NSHTTPURLResponse *)response;
_totalSize = httpRespone.expectedContentLength; // 获取下载文件的总大小
_fileName = httpRespone.suggestedFilename; // 下载文件的名
NSLog(@"%@", httpRespone);
// 获取响应头字段的value
// NSString *contentLength = httpRespone.allHeaderFields[@"Content-Length"]; // 也可以获取文件的总长度
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 拼接NSData
[self.downLoadData appendData:data];
// 计算进度
NSUInteger currLength = self.downLoadData.length;
double progress = (currLength * 1.0 / self.totalSize) * 100;
NSLog(@"------------------%@", [NSString stringWithFormat:@"%.2f%%", progress]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 下载完成将下载的Data写入沙河
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [path stringByAppendingPathComponent:self.fileName];
[self.downLoadData writeToFile:filePath options:kNilOptions error:nil];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
}
@end
NSURLSession下载小文件
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:@"http://img.zcool.cn/community/0142135541fe180000019ae9b8cf86.jpg@1280w_1l_2o_100sh.png"];
// 创建session
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSString *filePath = [FMFILE stringByAppendingPathComponent:response.suggestedFilename];
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
}];
// 执行task
[task resume];
}
NSURLSessionDownloadTask下载完文件后自动将文件临时存储在沙盒的tmp目录下,通过Block的location返回。我们需要将tmp目录下的文件剪切到要存储的目录下否则系统自动清理。
这里注意:[NSURL fileURLWithPath:filePath]
返回的URL是带有协议头的,而[NSURL URLWithString:@""];
返回的是不带协议头的URL。
因此开发中建议使用NSURLSessionDownloadTask下载小文件。
大文件下载
NSURLConnection下载大文件
大文件的下载不能像小文件下载的方式将服务器每次返回的data拼接到内存。而是需要边下载边写进沙盒
,这里需要使用NSFileHander
这个类。
#import "ViewController.h"
#define FMFILE NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject
@interface ViewController ()<NSURLConnectionDataDelegate>
/** 记录文件的总大小 */
@property (nonatomic, assign) long long totalLength;
/** 当前总长度 */
@property (nonatomic, assign) long long currLength;
@property (nonatomic, strong) NSFileHandle *handle;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_04.mp4"];
NSURLRequest *rquest = [NSURLRequest requestWithURL:url];
// 发送请求
[NSURLConnection connectionWithRequest:rquest delegate:self];
}
#pragma mark - NSURLConnectionDataDelegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// 下载完成将下载的Data写入沙河
NSHTTPURLResponse *httpRespone = (NSHTTPURLResponse *)response;
NSString *fileName = httpRespone.suggestedFilename; // 下载文件的名
NSString *filePath = [FMFILE stringByAppendingPathComponent:fileName];
// 接收到一个响应创建空的文件
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
self.totalLength = httpRespone.expectedContentLength; // 获取下载文件的总大小
self.handle = [NSFileHandle fileHandleForWritingAtPath:filePath];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 每次文件从文件内容尾部拼接
[self.handle seekToEndOfFile];
// 开始写入数据
[self.handle writeData:data];
// 拼接总长度
self.currLength += data.length;
// 计算当前进度
CGFloat progress = self.currLength * 1.0 / self.totalLength;
NSLog(@"下载进度----%.2f%%", progress *100);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self.handle closeFile];
self.handle = nil;
// 清零数据
self.currLength = 0;
self.totalLength = 0;
}
@end
NSURLSession下载大文件
#import "ViewController.h"
#define FMFILE NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject
@interface ViewController ()<NSURLSessionDownloadDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_04.mp4"];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url];
[task resume];
}
#pragma mark - NSURLSessionDataDelegate
/*
每当写入数据到临时文件就会调用该方法
bytesWritten 这次写入数据的长度
totalBytesWritten 已经写入的文件长度
totalBytesExpectedToWrite 要下载文件的中长度
*/
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
CGFloat progress = totalBytesWritten * 1.0 / totalBytesExpectedToWrite;
NSLog(@"----------%.2f%%", progress*100);
}
/*
恢复下载
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
}
// 现在完毕
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
NSString *filePath = [FMFILE stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
// 剪切文件
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
}
// 完成跟失败都会来到这个代理方法
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
NSLog(@"------------%s", __func__);
}
@end
NSURLSession断点下载大文件
NSURLSession创建的Task的的父类NSURLSessionTask有三个方法,因此它的子类都有这些方法。
我们就可以利用这几个方法做断点下载。
- (void)suspend;
- (void)resume;
- (void)cancel;