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"];
#define Vedio @"http://221.228.249.82/youku/697A5CA0CEB3582FB91C4E3A88/03002001004E644FA2997704E9D2A7BA1E7B9D-6CAB-79A9-E635-3B92A92B3500.mp4"
#define Picture @"http://x1.zhuti.com/down/2012/11/29-win7/3D-1.jpg"
- (IBAction)download:(id)sender
{
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
AFNetworking实现 断点续传的更多相关文章
- AFNetworking实现程序重新启动时的断点续传
今天需要用AFNetworking实现断点续传的功能,但是在进行了一番研究之后,发现AFNetworking虽然支持下载文件的暂停和继续,但是程序重新启动后再次下载无法进行续传.网上有说可以通过AFD ...
- AFNetworking 3.0 断点续传 使用记录
最近项目中用到了压缩包下载,使用AFNetworking 3.0 下载压缩包 支持断点续传 代码如下: #import "HDInternet_handler.h" #import ...
- AFNetworking 下载文件断点续传操作
一:本示例代码包括: 文件下载,写入指定目录 下载进度,回调Progress; 断点续传,下载暂停,继续操作: 二:本项目 适用于 AFNetworking 1.x 版本 #pragma mark 断 ...
- 使用 AFNetworking做过断点续传吗?
断点续传的主要思路: 检查服务器文件信息 检查本地文件 如果比服务器文件小, 断点续传, 利用 HTTP 请求头的 content-range实现断点续传(如果content-range不存在就取Co ...
- 【原】AFNetworking源码阅读(四)
[原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...
- 【原】AFNetworking源码阅读(三)
[原]AFNetworking源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇的话,主要是讲了如何通过构建一个request来生成一个data tas ...
- 总结iOS开发中的断点续传那些事儿
前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...
- AFNetworking到底做了什么?(二)
接着上一篇的内容往下讲,如果没看过上一篇内容可以点这: AFNetworking到底做了什么? 之前我们讲到NSUrlSession代理这一块: 代理8: /* task完成之后的回调,成功和失败 ...
- AFNetworking、MKNetworkKit和ASIHTTPRequest对比
之前一直在使用ASIHTTPRequest作为网络库,但是由于其停止更新,iOS7上可能出现更多的问题,于是决定更换网络库. 目前比较流行的网络库主要有AFNetworking和MKNetworkKi ...
随机推荐
- 使用Query 进行空值(empty)校验
效果如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...
- 国威电话机WS824(5D)-3型调试文档--可以转行啦
多了一万多搞的机器,花了我和同事们两三个晚上,最近还要打技术支持得到的经验... 可以转行作弱电啦啦~~~) 一,外线分组调试: 默认设置为所有内线端口可用1,2,13,14,15,16打出.(16个 ...
- javascript笔记6之函数
/* function box() { //函数的声明 alert('我只有被调用才可以执行!'); //函数本身没有运行功能 } //必须调用才可以执行 box(); //调用 function b ...
- PHP常用魔术方法(__set、__get魔术方法:)
__set.__get魔术方法: //文件名:Object.php <?phpnamespace IMooc;class Object{ protected $array = array(); ...
- SQL - 删掉数据库
ALTER DATABASE [DB_NAME]SET OFFLINEWITH ROLLBACK IMMEDIATEGODROP DATABASE [DB_NAME]GO
- how tomcat works 读书笔记(一)----------一个简单的webserver
http协议 若是两个人能正常的说话交流,那么他们间必然有一套统一的语言规则<在网络上server与client能交流也依赖与一套规则,它就是我们说的http规则(超文本传输协议Hypertex ...
- [Regex Expression] Use Shorthand to Find Common Sets of Characters
In this lesson we'll learn shorthands for common character classes as well as their negated forms. v ...
- oendir(),readdir(),closedir() 打开/读取/关闭目录
目录操作 当目标是目录而不是文件的时候,ls -l的结果会显示目录下所有子条目的信息,怎么去遍历整个目录呢?答案马上揭晓! 1. 打开目录 功能:opendir()用来打开参数name指定的目录,并返 ...
- android 新浪微博客户端的表情功能的实现
这是一篇好文章,我转来收藏,技术的最高境界是分享. 最近在搞android 新浪微博客户端,有一些心得分享弄android客户端表情功能可以用以下思路1.首页把新浪的表情下载到本地一文件夹种,表情图片 ...
- SELECT--UNION,UNION ALL,MINUS, INTERSECT,EXISTS
SELECT--UNION,UNION ALL,MINUS, INTERSECT返回两个查询结果的集合操作,两个查询结果集必须字段相同.UNION和UNION ALL并集操作,UNION并集后去掉重复 ...