zoukankan      html  css  js  c++  java
  • iOS开发系列-文件下载

    小文件下载

    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;
    
  • 相关阅读:
    Django of python 中文文档 及debug tool
    爬虫、网页测试 及 java servlet 测试框架等介绍
    python的分布式爬虫框架
    github 上 python 的优秀库推荐列表
    github 上 机器学习 的库推荐列表
    爬虫,如何防止被ban之策略大集合
    make menuconfig 时出现 mixed implicit and normal rules: deprecated syntax
    adb通过TCP/IP连接提示 unable to connect to *, Connection refused的解决方法
    Android中使用MediaCodec硬件解码,高效率得到YUV格式帧,快速保存JPEG图片(不使用OpenGL)(附Demo)
    ThinkCMF X2.2.2多处SQL注入漏洞分析
  • 原文地址:https://www.cnblogs.com/CoderHong/p/8896036.html
Copyright © 2011-2022 走看看