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 ...
随机推荐
- 十分钟让你的ASP.NET MVC网站变成PHP
昨天从网上看来的,某个人发的方法: 第一:修改一下路由: 把RouteConfig中的: routes.MapRoute( name: "Default", url: " ...
- 从汇编来看c语言
一. 学习过程 从C语言的角度提出一些问题,这些问题再从汇编的角度考虑,还真的很有意思. (1) 我们用高级语言编程时,一般不可能不用到变量,但是一定要用到变量吗?还有这些变量从汇编的角度是怎么实现的 ...
- Sogou搜狗搜索引擎登录网站 - Blog透视镜
Sogou搜狗是中国搜狐旗下的搜索引擎,其登录方式也很简单,只要输入网址,验证码即可,不需要注册账号,再进行登录,其他非 * 必填的字段,可留下空白不填,验证码只有4码,也很清晰可见,不像有的网站,即 ...
- android textview 行间距
设置行间距:android:lineSpacingExtra 设置行间距的倍数:android:lineSpacingMultiplier 如下:设置行间距为3,行间距倍数为1.5 <TextV ...
- Xmind 快捷键
Xmind 快捷键 快捷键(Windows) 快捷键(Mac) 描述 Ctrl+N Command+N 建立新工作簿 Ctrl+O Command+O 开启工作簿 Ctrl+S Command+S 储 ...
- bzoj 1191
http://www.lydsy.com/JudgeOnline/problem.php?id=1191 二分+二分图匹配. 首先二分可以答对前mid道题,然后做二分图. 左边是题目,右边是锦囊. 做 ...
- fstream读写UNICODE文件
今天遇到要处理UNICODE文件的情况,网上找了一圈都是读取出字节,再转的,这个不方便啊!想起了有codecvt这么个东西,顺藤摸瓜,找到了方法. locale utf16(locale(" ...
- [置顶] 单片机C语言易错知识点经验笔记
今天写这一篇文章并不是因为已经想好了一篇文章才写下来,而是我要将这一篇文章作为一个长期的笔记来写,我会一直更新.在进行单片机开发时,经常都会出现一些很不起眼的问题,这些问题其实都是很基础的c语言知识点 ...
- USB Video Class及其实现
1 Video Class 基础概念Usb协议中,除了通用的软硬件电气接口规范等,还包含了各种各样的Class协议,用来为不同的功能定义各自的标准接口和具体的总线上的数据交互格式和内容.这些Class ...
- [Redux] Generating Containers with connect() from React Redux (VisibleTodoList)
Learn how to use the that comes with React Redux instead of the hand-rolled implementation from the ...