zoukankan      html  css  js  c++  java
  • AFNetworking实现 断点续传

     

    用AFNetworking实现断点续传,暂停,继续

    AFNetworking的版本:
    platform:ios,'7.0'

    pod "AFNetworking","~> 2.3.0"

    简单思路:通过重组progressBlock , successBlock ,requestUrl ,outPutStream,然后利用AFNetworking自带的pause,resume即可妥妥的实现。

    不过碰到了一些问题也挺折磨人的,文件输入流,初始化就碰到问题了,
    1.[self.requestOperation setOutputStream:[NSOutputStream outputStreamToFileAtPath:self.cachePath() append:YES]
    如果追加了原始文件的data,就无法在下载过程中从outPutStream中获取到data。
     [self.requestOperation setOutputStream:[NSOutputStream outputStreamToFileAtPath:self.cachePath() append:NO]
    如果不追加,续传就成覆盖了。 

    官方文档也没仔细看,所幸就使用不追加的方式,然后手动同步文件与输入流。 方法如下

    -(void)readCacheToOutStreamWithPath:(NSString*)path;

    2.pause之后,AFHTTPRequestOperation.totalBytesRead,仍然记录这之前的读取长度,如果resume了,这是content-length发生了变法,这个时候就需要从组progressBlock了,同时也需要将totalBytesRead设为0,因为是私有属性,所以就用KVC。

              [self.requestOperation setValue:@"0" forKey:@"totalBytesRead"];
     
     
    ------------随便贴个VC----------------------
     

    - (IBAction)download:(id)sender

    {

    //http://202.102.88.133/youku/657114D0FE44481C592F964ABD/030020010053F4AB5FB92A01296A84C7E5A401-0FC6-BD65-4525-706B419E9EA6.mp4

    //    http://b.hiphotos.baidu.com/image/h%3D1200%3Bcrop%3D0%2C0%2C1920%2C1200/sign=b284ea7541a98226a7c12f25bab28262/960a304e251f95ca8888fab6cb177f3e670952b4.jpg

        NSString* path = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents/temp"];

        NSLog(@"path = %@",path);

        operation = [[DownLoadOperationalloc] init];

        [operationdownloadWithUrl:Picture

                         cachePath:^NSString *{

                             return path;

                         } progressBlock:^(NSUInteger bytesRead,long long totalBytesRead,long long totalBytesExpectedToRead) {

                             

                             NSLog(@"bytesRead = %u ,totalBytesRead = %llu totalBytesExpectedToRead = %llu",bytesRead,totalBytesRead,totalBytesExpectedToRead);

                             float progress = totalBytesRead / (float)totalBytesExpectedToRead;

                             

                             [self.progressViewsetProgress:progressanimated:YES];

                             

                             [self.labelsetText:[NSStringstringWithFormat:@"%.2f%%",progress*100]];

                             UIImage* image = [UIImageimageWithData:operation.requestOperation.responseData];

                             [self.imageViewsetImage:image];

                         } success:^(AFHTTPRequestOperation *operation,id responseObject) {

                             

                             NSLog(@"success");

    //                         UIImage* image = [UIImage imageWithData:operation.responseData];

    //                         [self.imageView setImage:image];

                             

                             

                             

                         } failure:^(AFHTTPRequestOperation *operation,NSError *error) {

                             NSLog(@"error = %@",error);

                         }];

        

        

    }

     
     
    ----------------------------------
     
     
     
     
     
     






    #import <Foundation/Foundation.h>

    #import "AFNetworking.h"

    @interface DownLoadOperation :NSObject

    @property(nonatomic ,strong) NSURL* url;

    @property(nonatomic ,copy) NSString* (^cachePath)(void);

    @property(nonatomic ,strong) AFHTTPRequestOperation* requestOperation;

    @property(nonatomic ,copy) void(^progressBlock)(NSUInteger bytesRead,long long totalBytesRead,long longtotalBytesExpectedToRead);

    -(void)downloadWithUrl:(id)url

                 cachePath:(NSString* (^) (void))cacheBlock

             progressBlock:(void (^)(NSUInteger bytesRead,long long totalBytesRead,long longtotalBytesExpectedToRead))progressBlock

                   success:(void (^)(AFHTTPRequestOperation *operation,id responseObject))success

                   failure:(void (^)(AFHTTPRequestOperation *operation,NSError *error))failure;

    @end

     


    #import "DownLoadOperation.h"

    @implementation DownLoadOperation

    -(void)downloadWithUrl:(id)url

                 cachePath:(NSString* (^) (void))cacheBlock

             progressBlock:(void (^)(NSUInteger bytesRead,long long totalBytesRead,long longtotalBytesExpectedToRead))progressBlock

                   success:(void (^)(AFHTTPRequestOperation *operation,id responseObject))success

                   failure:(void (^)(AFHTTPRequestOperation *operation,NSError *error))failure

    {

        

        self.cachePath = cacheBlock;

        //获取缓存的长度

        longlong cacheLength = [[selfclass] cacheFileWithPath:self.cachePath()];

        

        NSLog(@"cacheLength = %llu",cacheLength);

        

        //获取请求

        NSMutableURLRequest* request = [[selfclass] requestWithUrl:urlRange:cacheLength];

        

        

        self.requestOperation = [[AFHTTPRequestOperationalloc] initWithRequest:request];

        [self.requestOperationsetOutputStream:[NSOutputStreamoutputStreamToFileAtPath:self.cachePath()append:NO]];

        

        //处理流

        [selfreadCacheToOutStreamWithPath:self.cachePath()];

        

        

        [self.requestOperationaddObserver:selfforKeyPath:@"isPaused"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:nil];

      

        

        //获取进度块

        self.progressBlock = progressBlock;

        

        

        //重组进度block

        [self.requestOperationsetDownloadProgressBlock:[selfgetNewProgressBlockWithCacheLength:cacheLength]];

        

        

        //获取成功回调块

        void (^newSuccess)(AFHTTPRequestOperation *operation,id responseObject) = ^(AFHTTPRequestOperation *operation,idresponseObject){

            NSLog(@"responseHead = %@",[operation.responseallHeaderFields]);

            

            success(operation,responseObject);

        };

        

        [self.requestOperationsetCompletionBlockWithSuccess:newSuccess

                                                     failure:failure];

        [self.requestOperationstart];

        

        

    }

    #pragma mark - 获取本地缓存的字节

    +(longlong)cacheFileWithPath:(NSString*)path

    {

        NSFileHandle* fh = [NSFileHandlefileHandleForReadingAtPath:path];

        

        NSData* contentData = [fhreadDataToEndOfFile];

        return contentData ? contentData.length :0;

        

    }

    #pragma mark - 重组进度块

    -(void(^)(NSUInteger bytesRead,long long totalBytesRead,long longtotalBytesExpectedToRead))getNewProgressBlockWithCacheLength:(longlong)cachLength

    {

        typeof(self)newSelf =self;

        void(^newProgressBlock)(NSUInteger bytesRead,long long totalBytesRead,long long totalBytesExpectedToRead) = ^(NSUInteger bytesRead,long long totalBytesRead,long long totalBytesExpectedToRead)

        {

            NSData* data = [NSDatadataWithContentsOfFile:self.cachePath()];

            [self.requestOperationsetValue:dataforKey:@"responseData"];

    //        self.requestOperation.responseData = ;

            newSelf.progressBlock(bytesRead,totalBytesRead + cachLength,totalBytesExpectedToRead + cachLength);

        };

        

        return newProgressBlock;

    }

     

    #pragma mark - 读取本地缓存入流

    -(void)readCacheToOutStreamWithPath:(NSString*)path

    {

        NSFileHandle* fh = [NSFileHandlefileHandleForReadingAtPath:path];

        NSData* currentData = [fhreadDataToEndOfFile];

        

        if (currentData.length) {

            //打开流,写入data,未打卡查看 streamCode = NSStreamStatusNotOpen

            [self.requestOperation.outputStreamopen];

            

            NSInteger       bytesWritten;

            NSInteger       bytesWrittenSoFar;

            

            NSInteger  dataLength = [currentDatalength];

            constuint8_t * dataBytes  = [currentDatabytes];

            

            bytesWrittenSoFar = 0;

            do {

                bytesWritten = [self.requestOperation.outputStreamwrite:&dataBytes[bytesWrittenSoFar]maxLength:dataLength - bytesWrittenSoFar];

                assert(bytesWritten !=0);

                if (bytesWritten == -1) {

                    break;

                } else {

                    bytesWrittenSoFar += bytesWritten;

                }

            } while (bytesWrittenSoFar != dataLength);

            

            

        }

    }

    #pragma mark - 获取请求

    +(NSMutableURLRequest*)requestWithUrl:(id)url Range:(longlong)length

    {

        NSURL* requestUrl = [urlisKindOfClass:[NSURLclass]] ? url : [NSURLURLWithString:url];

        

        NSMutableURLRequest* request = [NSMutableURLRequestrequestWithURL:requestUrl

                                                              cachePolicy:NSURLRequestReloadIgnoringCacheData

                                                          timeoutInterval:5*60];

        

        

        if (length) {

            [request setValue:[NSStringstringWithFormat:@"bytes=%lld-",length]forHTTPHeaderField:@"Range"];

        }

        

        NSLog(@"request.head = %@",request.allHTTPHeaderFields);

        

        return request;

    }

    #pragma mark - 监听暂停

    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context

    {

        NSLog(@"keypath = %@ changeDic = %@",keyPath,change);

        //暂停状态

        if ([keyPathisEqualToString:@"isPaused"] && [[changeobjectForKey:@"new"]intValue] ==1) {

            

           

            

            longlong cacheLength = [[selfclass] cacheFileWithPath:self.cachePath()];

            //暂停读取data从文件中获取到NSNumber

            cacheLength = [[self.requestOperation.outputStreampropertyForKey:NSStreamFileCurrentOffsetKey]unsignedLongLongValue];

            NSLog(@"cacheLength = %lld",cacheLength);

            [self.requestOperationsetValue:@"0"forKey:@"totalBytesRead"];

            //重组进度block

            [self.requestOperationsetDownloadProgressBlock:[selfgetNewProgressBlockWithCacheLength:cacheLength]];

        }

    } 

    @end

     
  • 相关阅读:
    IDEA手动创建JFinal项目(404问题处理)
    php 把数字1-1亿换成汉字表述,例如 150 转成 一百五十
    模仿console自写函数打印js的对象
    每瓶啤酒2元,2个空酒瓶或4个瓶盖可换1瓶啤酒。10元最多可喝多少瓶啤酒? php
    js-Event构造函数,也许你需要
    js将金额专成每隔3位数加逗号
    js-PC版监听键盘大小写事件
    用php脚本给html中引用的js和css路径打上版本
    通过js的console优雅的将php调试信息输出
    android中加载的html获取的宽高不正确
  • 原文地址:https://www.cnblogs.com/iOS-mt/p/4320371.html
Copyright © 2011-2022 走看看