zoukankan      html  css  js  c++  java
  • 【iOS】文件下载小记

    文件的下载分为NSURLConnectionNSURLSession两种,前一种有恨悠久的历史了。使用相对麻烦,后者是新出来的,增加了一些额外的功能。

    一、NSURLConnection实现下载

    TIPS:

    1、当NSURLConnection下载时,得到的NSData写入文件时,data并没有占用多大内存. (即使文件很大)
    2、一点点在传. 做的是磁盘缓存.而不是内存缓存机制。

    3、了解在NSURLConnection上加代理。[consetDelegateQueue:[[NSOperationQueuealloc]init]]

    4、NSURLResponse记录的了url, mineType, exceptedContentLength, suggestedFileName等属性. 下载时用得着.  

    以下程序实现追踪下载百分比的下载(URLConnection自带的方法):

    [objc] view plaincopy
     
    1. #import "XNDownload.h"  
    2.   
    3. typedef void(^ProgressBlock)(float percent);  
    4.   
    5. @interface XNDownload() <NSURLConnectionDataDelegate>  
    6.   
    7. @property (nonatomic, strong) NSMutableData *dataM;  
    8.   
    9. // 保存在沙盒中的文件路径  
    10. @property (nonatomic, strong) NSString *cachePath;  
    11. // 文件总长度  
    12. @property (nonatomic, assign) long long fileLength;  
    13. // 当前下载的文件长度  
    14. @property (nonatomic, assign) long long currentLength;  
    15.   
    16. // 回调块代码  
    17. @property (nonatomic, copy) ProgressBlock progress;  
    18.   
    19. @end  
    20.   
    21. @implementation XNDownload  
    22.   
    23. - (NSMutableData *)dataM  
    24. {  
    25.     if (!_dataM) {  
    26.         _dataM = [NSMutableData data];  
    27.     }  
    28.     return _dataM;  
    29. }  
    30.   
    31. - (void)downloadWithURL:(NSURL *)url progress:(void (^)(float))progress  
    32. {  
    33.     // 0. 记录块代码  
    34.     self.progress = progress;  
    35.       
    36.     // 1. request GET  
    37.     NSURLRequest *request = [NSURLRequest requestWithURL:url];  
    38.       
    39.     // 2. connection  
    40.     NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];  
    41.       
    42.     // 让connection支持多线程,指定代理的工作队列即可  
    43.     // NSURLConnection在运行时,运行循环不负责监听代理的具体执行  
    44.     [connection setDelegateQueue:[[NSOperationQueue alloc] init]];  
    45.       
    46.     // 3. 启动连接  
    47.     [connection start];  
    48. }  
    49.   
    50. #pragma mark - 代理方法  
    51. // 1. 接收到服务器的响应,服务器执行完请求,向客户端回传数据  
    52. - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response  
    53. {  
    54.     NSLog(@"%@ %lld", response.suggestedFilename, response.expectedContentLength);  
    55.     // 1. 保存的缓存路径  
    56.     NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];  
    57.     self.cachePath = [cachePath stringByAppendingPathComponent:response.suggestedFilename];  
    58.     // 2. 文件总长度  
    59.     self.fileLength = response.expectedContentLength;  
    60.     // 3. 当前下载的文件长度  
    61.     self.currentLength = 0;  
    62.       
    63.     // 清空数据  
    64.     [self.dataM setData:nil];  
    65. }  
    66.   
    67. // 2. 接收数据,从服务器接收到数据  
    68. - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data  
    69. {  
    70.     // 拼接数据  
    71.     [self.dataM appendData:data];  
    72.       
    73.     // 根据data的长度增加当前下载的文件长度  
    74.     self.currentLength += data.length;  
    75.       
    76.     float progress = (float)self.currentLength / self.fileLength;  
    77.       
    78.     // 判断是否定义了块代码  
    79.     if (self.progress) {  
    80.         [[NSOperationQueue mainQueue] addOperationWithBlock:^{  
    81.             // 强制运行循环执行一次更新  
    82.             [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];  
    83.               
    84.             self.progress(progress);  
    85.         }];  
    86.     }  
    87. }  
    88.   
    89. // 3. 完成接收  
    90. - (void)connectionDidFinishLoading:(NSURLConnection *)connection  
    91. {  
    92.     NSLog(@"%s %@", __func__, [NSThread currentThread]);  
    93.     // 将dataM写入沙盒的缓存目录  
    94.     // 写入数据,NSURLConnection底层实现是用磁盘做的缓存  
    95.     [self.dataM writeToFile:self.cachePath atomically:YES];  
    96. }  
    97.   
    98. // 4. 出现错误  
    99. - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error  
    100. {  
    101.     NSLog(@"%@", error.localizedDescription);  
    102. }  
    103.   
    104. @end  


    二、NSURLSession实现下载

    NSURLSession能实现断点续传,暂停下载等功能。

    1、session提供的是开了多个线程的异步下载.
    2、下载的暂停与续传: (session的代理中的方法)
    *弄一个NSData变量来保存下载东西.暂停时将下载任务task清空.
    *续传:将暂停时的data交给session继续下载,并将先前的data清空.
    3、task一定要resume才开始执行.
    [objc] view plaincopy
     
      1. #import "XNViewController.h"  
      2.   
      3. @interface XNViewController () <NSURLSessionDownloadDelegate>  
      4.   
      5. // 下载网络回话  
      6. @property (nonatomic, strong) NSURLSession *session;  
      7. // 下载任务  
      8. @property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;  
      9. // 续传的二进制数据  
      10. @property (nonatomic, strong) NSData *resumeData;  
      11. @end  
      12.   
      13. @implementation XNViewController  
      14.   
      15. - (NSURLSession *)session  
      16. {  
      17.     if (!_session) {  
      18.         NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];  
      19.         _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];  
      20.     }  
      21.     return _session;  
      22. }  
      23.   
      24. - (void)viewDidLoad  
      25. {  
      26.     [super viewDidLoad];  
      27.       
      28.     [self downloadFile];  
      29. }  
      30.   
      31. // 暂停下载任务  
      32. - (IBAction)pause  
      33. {  
      34.     // 如果下载任务不存在,直接返回  
      35.     if (self.downloadTask == nil) return;  
      36.       
      37.     // 暂停任务(块代码中的resumeData就是当前正在下载的二进制数据)  
      38.     // 停止下载任务时,需要保存数据  
      39.     [self.downloadTask cancelByProducingResumeData:^(NSData *resumeData) {  
      40.         self.resumeData = resumeData;  
      41.           
      42.         // 清空并且释放当前的下载任务  
      43.         self.downloadTask = nil;  
      44.     }];  
      45. }  
      46.   
      47. - (IBAction)resume  
      48. {  
      49.     // 要续传的数据是否存在?  
      50.     if (self.resumeData == nil) return;  
      51.       
      52.     // 建立续传的下载任务  
      53.     self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];  
      54.     [self.downloadTask resume];  
      55.       
      56.     // 将此前记录的续传数据清空  
      57.     self.resumeData = nil;  
      58. }  
      59.   
      60. // 如果在开发中使用到缓存目录,一定要提供一个功能,“清除缓存”!  
      61. /** 下载文件 */  
      62. - (void)downloadFile  
      63. {  
      64.     NSString *urlStr = @"http://localhost/苍老师全集.rmvb";  
      65.     urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];  
      66.       
      67.     NSURL *url = [NSURL URLWithString:urlStr];  
      68.   
      69.     // (1) 代理 & 直接启动任  
      70.     // 2. 启动下载任务  
      71.     self.downloadTask = [self.session downloadTaskWithURL:url];  
      72.       
      73.     [self.downloadTask resume];  
      74. }  
      75.   
      76. #pragma mark - 下载代理方法  
      77. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location  
      78. {  
      79.     NSLog(@"完成 %@ %@", location, [NSThread currentThread]);  
      80. }  
      81.   
      82. /** 
      83.  bytesWritten               : 本次下载的字节数 
      84.  totalBytesWritten          : 已经下载的字节数 
      85.  totalBytesExpectedToWrite  : 下载总大小 
      86.  */  
      87. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite  
      88. {  
      89.     float progress = (float)totalBytesWritten / totalBytesExpectedToWrite;  
      90.       
      91.     [[NSOperationQueue mainQueue] addOperationWithBlock:^{  
      92.         //主线程中更新进度UI操作。。。。  
      93.     }];  
      94. }  
      95.   
      96. /** 续传的代理方法 */  
      97. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes  
      98. {  
      99.     NSLog(@"offset : %lld", fileOffset);  
      100. }  
      101.   
      102. @end  
  • 相关阅读:
    递推最小二乘辨识平面双机械臂Matlab代码
    Matlab Robitic Toolbox学习笔记Day2
    DSP28335与CH340使用心得
    DSP 28335 GPIO输入引脚信号跳变
    DSP 28335 RS485 SCI串口通讯 出错无法进入中断
    DSP 28335 烧写FLASH程序 可以在线仿真 无法离线运行
    CRC16-Modbus 校验 C语言
    C语言 负数转十六进制 电机转速 CANopen命令转换
    CAN转USB 调试助手使用说明
    串的模式匹配 BF算法&KMP算法
  • 原文地址:https://www.cnblogs.com/lvfeilong/p/58349058lkjglkf.html
Copyright © 2011-2022 走看看