zoukankan      html  css  js  c++  java
  • iOS项目开发—文件下载功能的实现

    一、简单说明

     

    1.思路

    把下载的data追加到文件的尾部,直到所有的数据下载完为止。

    1.在连通了服务器的时候,创建一个空的文件到沙盒中NSFileManager(文件管理类)

    2.创建写数据的文件句柄

    3.在接收到服务器返回的数据后,把data写入到创建的空文件中,但是不能使用writeTofile(会覆盖)

    3.1移动到文件的尾部

    3.2从当前移动的位置,写入数据

    4.服务器的数据加载完毕后关闭连接,不再输入数据在文件中

    二、代码示例

    1.代码:

    新建一个类,让其继承自NSObject类,一个文件下载器只下载一个文件。

    自定义类的TXFileDownloader.h代码:

     1 //
     2 //  TXFileDownloader.h
     3 //  文件下载
     4 //
     5 //  Created by 鑫 on 14/12/23.
     6 //  Copyright (c) 2014年 梁镋鑫. All rights reserved.
     7 //
     8 
     9 #import <Foundation/Foundation.h>
    10 
    11 @interface TXFileDownloader : NSObject
    12 //下载的远程url(连接到服务器的路径)
    13 @property(nonatomic,strong)NSString *url;
    14 //下载后的存储路径(文件下载到什么地方)
    15 @property(nonatomic,strong)NSString *destPath;
    16 //是否正在下载(只有下载器内部清楚)
    17 @property(nonatomic,readonly,getter = isDownloading)BOOL Downloading;
    18 //用来监听下载进度
    19 @property(nonatomic,copy)void (^progressHandler)(double progress);
    20 //用来监听下载完成
    21 @property(nonatomic,copy)void (^completionHandler)();
    22 //用来监听下载错误
    23 @property(nonatomic,copy)void(^failureHandler)(NSError *error);
    24 -(void)pause;
    25 -(void)start;
    26 @end

    自定义类的TXFileDownloader.m

      1 //  TXFileDownloader.m
      2 //  文件下载
      3 //
      4 //  Created by 鑫 on 14/12/23.
      5 //  Copyright (c) 2014年 梁镋鑫. All rights reserved.
      6 //
      7 
      8 #import "TXFileDownloader.h"
      9 @interface TXFileDownloader ()<NSURLConnectionDataDelegate>
     10 //请求对象
     11 @property(nonatomic,strong)NSURLConnection *cnnt;
     12 //文件句柄
     13 @property(nonatomic,strong)NSFileHandle *writeHandle;
     14 //当前获取到的数据长度
     15 @property(nonatomic,assign)long long currentLength;
     16 //完整数据长度
     17 @property(nonatomic,assign)long long sumLength;
     18 @end
     19 
     20 @implementation TXFileDownloader
     21 //开始下载
     22 -(void)start
     23 {
     24     _Downloading=YES;
     25     
     26     //创建一个请求
     27     NSURL *URL=[NSURL URLWithString:self.url];
     28     NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:URL];
     29     
     30     //设置请求头信息
     31     //self.currentLength字节部分重新开始读取
     32     NSString *value=[NSString stringWithFormat:@"bytes=%lld-",self.currentLength];
     33     [request setValue:value forHTTPHeaderField:@"Range"];
     34     
     35     //发送请求(使用代理的方式)
     36     self.cnnt=[NSURLConnection connectionWithRequest:request delegate:self];
     37     
     38 }
     39 
     40 //暂停下载
     41 -(void)pause
     42 {
     43     _Downloading=NO;
     44     //取消发送请求
     45     [self.cnnt cancel];
     46     self.cnnt=nil;
     47 }
     48 
     49 #pragma mark- NSURLConnectionDataDelegate代理方法
     50 /*
     51  *当接收到服务器的响应(连通了服务器)时会调用
     52  */
     53 -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
     54 {
     55 #warning 判断是否是第一次连接
     56     if (self.sumLength) return;
     57     
     58     //1.创建文件存数路径
     59     NSString *caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
     60     NSString *filePath=[caches stringByAppendingPathComponent:@"video.zip"];
     61     
     62     
     63     
     64     //2.创建一个空的文件,到沙盒中
     65     NSFileManager *mgr=[NSFileManager defaultManager];
     66     //刚创建完毕的大小是o字节
     67     [mgr createFileAtPath:filePath contents:nil attributes:nil];
     68     
     69     //3.创建写数据的文件句柄
     70     self.writeHandle=[NSFileHandle fileHandleForWritingAtPath:filePath];
     71     
     72     //4.获取完整的文件长度
     73     self.sumLength=response.expectedContentLength;
     74 }
     75 
     76 /*
     77  *当接收到服务器的数据时会调用(可能会被调用多次,每次只传递部分数据)
     78  */
     79 -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
     80 {
     81     //累加接收到的数据长度
     82     self.currentLength+=data.length;
     83     //计算进度值
     84     double progress=(double)self.currentLength/self.sumLength;
     85     //    self.progress.progress=progress;
     86     if (self.progressHandler) {//传递进度值给block
     87         self.progressHandler(progress);
     88         
     89         //相当于在此处调用了下面的代码
     90         //        ^(double progress)
     91         //        {
     92         //            //把进度的值,传递到控制器中进度条,以进行显示
     93         //            vc.progress.progress=progress;
     94         //        };
     95     }
     96     
     97     
     98     //一点一点接收数据。
     99     NSLog(@"接收到服务器的数据!---%d",data.length);
    100     //把data写入到创建的空文件中,但是不能使用writeTofile(会覆盖)
    101     //移动到文件的尾部
    102     [self.writeHandle seekToEndOfFile];
    103     //从当前移动的位置,写入数据
    104     [self.writeHandle writeData:data];
    105 }
    106 
    107 /*
    108  *当服务器的数据加载完毕时就会调用
    109  */
    110 -(void)connectionDidFinishLoading:(NSURLConnection *)connection
    111 {
    112     NSLog(@"下载完毕----%lld",self.sumLength);
    113     //关闭连接,不再输入数据在文件中
    114     [self.writeHandle closeFile];
    115     self.writeHandle=nil;
    116     
    117     //清空进度值
    118     self.currentLength=0;
    119     self.sumLength=0;
    120     
    121     if (self.completionHandler) {//下载完成通知控制器
    122         self.completionHandler();
    123         //相当于下面的代码
    124         //        ^{
    125         //            NSLog(@"下载完成");
    126         //            [self.btn setTitle:@"下载已经完成" forState:UIControlStateNormal];
    127         //        }
    128     }
    129     
    130 }
    131 /*
    132  *请求错误(失败)的时候调用(请求超时断网没有网,一般指客户端错误)
    133  */
    134 -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    135 {
    136     if (self.failureHandler) {//通知控制器,下载出错
    137         self.failureHandler(error);
    138         //相当于调用了下面的代码
    139         //        ^{
    140         //            NSLog(@"下载错误!");
    141         //        }
    142     }
    143 }
    144 
    145 @end
    View Code

    实现代码:

    主控制器TXViewController.m

     1 //
     2 //  TXViewController.m
     3 //  文件下载
     4 //
     5 //  Created by 鑫 on 14/12/23.
     6 //  Copyright (c) 2014年 梁镋鑫. All rights reserved.
     7 //
     8 
     9 #import "TXViewController.h"
    10 #import "TXFileDownloader.h"
    11 @interface TXViewController ()
    12 
    13 
    14 @property(nonatomic,strong)TXFileDownloader *fileDownloader;
    15 @property (weak, nonatomic) IBOutlet UIButton *btn;
    16 @property (weak, nonatomic) IBOutlet UIProgressView *progress;
    17 @end
    18 
    19 @implementation TXViewController
    20 
    21 - (void)viewDidLoad
    22 {
    23     [super viewDidLoad];
    24 }
    25 
    26 #pragma mark-懒加载
    27 -(TXFileDownloader *)fileDownloader
    28 {
    29     if (_fileDownloader==nil) {
    30         _fileDownloader=[[TXFileDownloader alloc]init];
    31         //设置文件下载路径
    32         _fileDownloader.url=@"http://192.168.1.53:8080/MJServer/resources/video.zip";
    33         
    34         //设置文件保存路径
    35         NSString *caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    36         NSString *filePath=[caches stringByAppendingPathComponent:@"video.zip"];
    37         _fileDownloader.destPath=filePath;
    38         
    39         //获取10的真实类型,把它作为a的类型
    40         //        typeof(10) a = 20; // int a = 20;
    41         __weak typeof(self) vc=self;
    42         _fileDownloader.progressHandler=^(double progress)
    43         {
    44             vc.progress.progress=progress;
    45             NSLog(@"%f",progress);
    46         };
    47         _fileDownloader.completionHandler=^{
    48             NSLog(@"下载完成");
    49             [vc.btn setTitle:@"下载已经完成" forState:UIControlStateNormal];
    50         };
    51         _fileDownloader.failureHandler=^(NSError *error){
    52             NSLog(@"下载错误!%@",error);
    53         };
    54     }
    55     return _fileDownloader;
    56 }
    57 
    58 //点击下载按钮,处理操作
    59 - (IBAction)star {
    60     if (self.fileDownloader.isDownloading) {//如果正在下载,那么调用方法暂停
    61         [self.fileDownloader pause];
    62         [self.btn setTitle:@"暂停" forState:UIControlStateNormal];
    63     }else//如果没有正在下载,那么调用下载方法
    64     {
    65         [self.fileDownloader start];
    66         [self.btn setTitle:@"下载" forState:UIControlStateNormal];
    67     }
    68 }
    69 
    70 @end
    View Code

    代码:

     

    控制器想监听下载器的下载进度,控制器想监听下载器的下载完毕,控制器想监听下载器的下载失败等都可以使用block的方式进行。

    打印查看:

    2.代码说明

    (1)创建文件存储路径(写入到沙盒)

     NSString *caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];

     NSString *filePath=[caches stringByAppendingPathComponent:@"video.zip"];

    (2)创建一个空的文件夹( NSFileManager类的使用)

     NSFileManager *mgr=[NSFileManager defaultManager];

    (3)创建写数据的文件句柄

          self.writeHandle=[NSFileHandle fileHandleForWritingAtPath:filePath];

    (4)把data写入到创建的空文件中,但是不能使用writeTofile(会覆盖)

    移动句柄到文件的尾部     [self.writeHandle seekToEndOfFile];

    (5)下载完毕的时候,关闭连接

    [self.writeHandle closeFile];

    3、Range简单说明

    通过设置请求头Range可以指定每次从网路下载数据包的大小

    Range示例

    bytes=0-499 从0到499的头500个字节

    bytes=500-999 从500到999的第二个500字节

    bytes=500- 从500字节以后的所有字节 

    bytes=-500 最后500个字节

    bytes=500-599,800-899 同时指定几个范围

    Range小结

    - 用于分隔

    前面的数字表示起始字节数

    后面的数组表示截止字节数,没有表示到末尾

    , 用于分组,可以一次指定多个Range,不过很少用

    注意:关键代码

            从self.currentLength字节部分重新开始读取

            NSString *value=[NSString stringWithFormat:@"bytes=%lld-",self.currentLength];

            [request setValue:value forHTTPHeaderField:@"Range"];

  • 相关阅读:
    iOS 改变同一个label中多行文字间的距离
    iOS改变UITableViewCell的分割线frame和颜色
    iOS动画实现改变frme和contenOffset
    iOS判断数组不为空
    jQueryMobile控件之ListView
    jQueryMobile控件之展开与合并
    jQueryMobile控件之页面切换
    jQueryMobile控件之按钮
    jQueryMobile控件之复选框
    jQueryUI 之控件们
  • 原文地址:https://www.cnblogs.com/asd5551680/p/4180431.html
Copyright © 2011-2022 走看看