zoukankan      html  css  js  c++  java
  • iOS-文件断点续传

    * 移动客户端在和服务器交互的时候,上传和下载使用十分广泛。

    * 在我们下载文件的时候,我们在点击暂停的时候可以暂停下载,点击下载的时候可以继续下载,这个功能如何实现?

    * 下载进度条如何显示?

    先大概叙述一下断点下载的原理:

    * 首先先判断要判断要下载的文件在本地沙盒中是否存在。

    * 如果存在的话,要判断下载文件的长度。

    * 假设文件长度是500,我们发起下载请求的时候应该从500开始。

    * 点击暂停下载,应该将链接断掉。

    * 再次点击下载的时候,根据下载文件长度,继续下载。

    下面与代码结合起来叙述具体的实现:

    * 假设我们要下载的文件在服务器的路径为:http://localhost:8080:down/xcode_6.dmg;

    * 我们将要下载的文件方法本地沙盒中。文件命名为:xcode.dmg.

    * 获取文件保存路径的代码:(折叠)

    1 -(NSString *)getFilePath
    2 {
    3     NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    4     NSString *filePath = [documentsPath stringByAppendingPathComponent:@"xcode.dmg"];
    5     return filePath;
    6 }
    下载文件保存路径

    * 因为下载的文件比较大,我们需要采取异步请求网络。

    * 异步请求网络常用的有四个代理方法。

    * 发起网络请求下载。(下载起始点为上次暂停点,判断上次暂停位置方法是,获取文件属性,从属性中可以查看文件长度,请求点为该长度后面的内容)

    * 假设向获取某个字节的内容,可以使用:

        //bytes = 0-499 请求前500个字节的内容

        //bytes = 500- 请求500字节之后的内容

        //bytes = 500-1000 请求资源中某一范围的内容

        //bytes = 0-1,499-500 请求多个范围之间的内容

    * 进度条过去文件下载进度,可以使用已经下载的文件的字节数/文件的总字节数。

    下面为具体的代码段,里面有详细的注释:

    #import <UIKit/UIKit.h>
    
    @interface ViewController : UIViewController<NSURLConnectionDataDelegate>
    {
        //进度条变量,显示文件下载进度
        IBOutlet UIProgressView *_progress;
        //文件处理,将下载的文件写入本地沙盒
        NSFileHandle *_fileHandle;
        //url连接,点解暂停,取消连接,点击下载,开始下载
        NSURLConnection *_connection;
        //已经接收数据大小
        long long _receiveSize;
        //文件总共的大小
        long long _totalSize;
    }
    
    //下载按钮点击响应函数
    - (IBAction)download:(id)sender;
    //暂停按钮点击响应函数
    - (IBAction)pause:(id)sender;
    
    @end
    
    - (IBAction)download:(id)sender
    {
        //文件的路径
        NSString *string = @"http://localhost:8080/down/xcode_6.dmg";
        //文件的路径转化为url
        NSURL *url = [NSURL URLWithString:string];
        //创建可变请求
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        //判断沙盒路径下有没有这个文件,YES表示这个文件已经下载,NO表示还没有下载
        if ([[NSFileManager defaultManager] fileExistsAtPath:[self getFilePath]] == YES)
        {
            
            //根据文件的属性,获取之前下载数据量是多少
            NSDictionary *fileDic = [[NSFileManager defaultManager]attributesOfItemAtPath:[self getFilePath] error:nil];
            //文件的长度就是已经下载的数据量
            _receiveSize = [fileDic[NSFileSize] longLongValue];
            //设置Range,从Range之后的内容开始下载
            //bytes = 0-499 请求前500个字节的内容
            //bytes = 500- 请求500字节之后的内容
            //bytes = 500-1000 请求资源中某一范围的内容
            //bytes = 0-1,499-500 请求多个范围之间的内容
            NSString *bytes = [NSString stringWithFormat:@"bytes=%lld-",_receiveSize];
            [request setValue:bytes forHTTPHeaderField:@"Range"];
            
        }
        //发起异步请求,文件比较法,使用异步请求
        _connection = [NSURLConnection connectionWithRequest:request delegate:self];
    }
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        //分析响应头
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        //获取响应头,是一个字典
        NSDictionary *responseHeader = httpResponse.allHeaderFields;
        //接收文件总的大小等于已经下载的数据量,加上为下载的数据量
        _totalSize = _receiveSize + [responseHeader[@"Content-Length"] longLongValue];
        //创建文件管理类
        NSFileManager *fileManager = [NSFileManager defaultManager];
        //沙盒中不存在要下载的文件,就创建该文件
        if ([fileManager fileExistsAtPath:[self getFilePath]] == NO)
        {
            [fileManager createFileAtPath:[self getFilePath] contents:nil attributes:nil];
        }
        //根据路径写入文件
        _fileHandle = [NSFileHandle fileHandleForWritingAtPath:[self getFilePath]];
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        //文件比较大的话,需要多次写入,写入的话,需要将光标定位到结尾
        [_fileHandle seekToEndOfFile];
        //将数据写入到文件
        [_fileHandle writeData:data];
        //最新接收到数据的大小等于文件中已有的数据,加上刚刚下载的数据量
        _receiveSize = _receiveSize + data.length;
        //计算进度
        float jundu = (float)_receiveSize / _totalSize;
        //使用进度条来表示进度
        _progress.progress = jundu;
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
        //文件完成传输,关闭文件管理
        [_fileHandle closeFile];
    }
    
    - (IBAction)pause:(id)sender
    {
        //点击暂停,取消请求连接
        [_connection cancel];
        _connection = nil;
    }
    
    -(NSString *)getFilePath
    {
        NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
        NSString *filePath = [documentsPath stringByAppendingPathComponent:@"xcode.dmg"];
        return filePath;
    }
    
  • 相关阅读:
    算法练习(16)-水平翻转一颗二叉树
    算法练习(15)-设计1个二叉树的序列化与反序列化实现?
    算法练习(14)-二叉树中2个节点的最近公共祖先?
    算法练习(13)-打印纸条对折的折痕类型(凹痕?凸痕?)
    算法练习(12)-二叉树的递归套路
    算法练习(11)-二叉树的各种遍历
    算法练习(10)-求2个(可能有环的)单链表的相交节点
    算法练习(9)-复杂带随机指针的单链表
    mac升级后第三方下载程序无法打开cannot be opened because the developer cannot be verified的解决办法
    算法练习(8)-判断单链表是否回文链表
  • 原文地址:https://www.cnblogs.com/wangyaoguo/p/4816607.html
Copyright © 2011-2022 走看看