最近在研究視頻下載的內容,下載的時候須要實現斷點續傳,上網查了不少資料,大部分都是程序運行時能夠實現斷點續傳,可是程序退出後,再次進入又得從頭開始,因此研究了好幾天,總結了如下幾種可以實現程序從新運行時斷點續傳的方法,廢話很少說,進入正題。git
一共三種方法:(1)基於AFNetworking的AFDownloadRequestOperation(這個框架能夠在gitHub上下載)。(2)NSURLConnection (3)AFNetworking程序員
對於一個程序員,代碼是最好的溝通工具,因此,直接上代碼。緩存
第一種方法:AFDownloadRequestOperation這個類已經爲咱們封裝好了斷點續傳的方法,因此咱們不不須要再設置。安全
首先在h文件中app
@interface ViewController : UIViewController<ASIHTTPRequestDelegate,ASIProgressDelegate>框架
//顯示進度的進度條工具
@property (weak, nonatomic) IBOutlet UIProgressView *myProgress;atom
//顯示已下載文件和文件總大小的比例。url
@property (weak, nonatomic) IBOutlet UILabel *sizeLabel;spa
//顯示當前下載狀況的label(單位:M)
@property (weak, nonatomic) IBOutlet UILabel *currentLabel;
//顯示文件的總大小(單位:M)
@property (weak, nonatomic) IBOutlet UILabel *totalLabel;
@property (nonatomic, strong)ASIHTTPRequest * request;
@property (nonatomic, strong)AFDownloadRequestOperation *operation;
// ********************************************************/
在viewController的m文件中
- (void)viewDidLoad {
[super viewDidLoad];
//建立下載文件的URL
NSURL * url = [NSURL URLWithString:@"http://182.92.5.120/d/file/20150210/lrKXiNVNwfyns/1/mp4/1_1.mp4"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:3600];
//建立文件路徑
NSString * path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) lastObject];
NSString * destionPath = [path stringByAppendingPathComponent:@"mp4"];
self.operation = [[AFDownloadRequestOperation alloc] initWithRequest:request targetPath:destionPath shouldResume:YES];
//當下載成功後會執行的方法
[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Successfully downloaded file to %@", destionPath);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
__block ViewController * viewVC = self;(防止循環引用形成內存泄漏,因此用block修飾一下)
//當在下載的時候,會一直調用這個方法,只要是如今在進行,此方法就一直執行,因此通常顯示進度,顯示下載文件大小的代碼都寫在這個方法裏面。
[self.operation setProgressiveDownloadProgressBlock:^(AFDownloadRequestOperation *operation, NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpected, long long totalBytesReadForFile, long long totalBytesExpectedToReadForFile) {
float percentDone = totalBytesReadForFile/(float)totalBytesExpectedToReadForFile;
viewVC.myProgress.progress = percentDone;
viewVC.sizeLabel.text = [NSString stringWithFormat:@"%.0f%%",percentDone*100];
viewVC.currentLabel.text= [NSString stringWithFormat:@"CUR : %lli M",totalBytesReadForFile/1024/1024];
viewVC.totalLabel.text = [NSString stringWithFormat:@"TOTAL : %lli M",totalBytesExpectedToReadForFile/1024/1024];
NSLog(@"1");
}];
- (IBAction)Start:(UIButton *)sender {
[self.operation start];
}
AFDownloadRequestOperation 這個類自己封裝方法已經寫好,咱們點用pause就是暫停,暫停後調用resume方法後就是斷點續傳,不虛設置其餘的。
- (IBAction)Pause:(UIButton *)sender {
[self.operation pause];
}
- (IBAction)goon:(UIButton *)sender {
[self.operation resume];
}
代碼寫到這裏,一個簡單的斷點續傳的小demo就寫好了。
第二種方法:NSURLConnection
如今大部分開發者都不用NSURLConnection進行數據請求了,大部分都是在用af,你們都以爲NSURLConnection用起來特別麻煩,可是我一直都是在用NSURLConnection,以爲NSURLConnection雖然用法複雜,可是仍是有必定優點的。直接上代碼
首先在viewController的h文件中
@property (weak, nonatomic) IBOutlet UIProgressView *myProgress;
//下載的url
@property (nonatomic, strong)NSString * url;
//用來監聽下載進度
@property (nonatomic, copy)void (^progressHandle)(double progress);
//用來監聽下載完成
@property (nonatomic, copy)void (^completionHandler)();
//用來監聽下載失敗
@property(nonatomic,copy)void(^failureHandler)(NSError *error);
@property (nonatomic, copy)NSString * name;
//已下載文件的大小
@property (nonatomic, assign)long long currentLength;
//文件的總大小
@property (nonatomic, assign)long long sumLength;
//請求對象
@property (nonatomic, strong)NSURLConnection * connection;
//文件句柄
@property (nonatomic, strong)NSFileHandle * writeHandle;
在viewController的m文件中
- (void)start
{
NSURL * url = [NSURL URLWithString:@"http://182.92.5.120/d/file/20150210/lrKXiNVNwfyns/1/mp4/1_1.mp4"];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
//設置請求頭信息;
接下來的兩句代碼就就是爲咱們斷點續傳的關鍵,若是沒有這兩句是沒法實現斷點續傳的。
NSString *value=[NSString stringWithFormat:@"bytes=%lld-",self.currentLength];
[request setValue:value forHTTPHeaderField:@"Range"];
//發送請求(使用代理的方式)
self.connection=[NSURLConnection connectionWithRequest:request delegate:self];
[self.connection start];
}
NSUTLConnection的代理方法
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
設置存放路徑
NSString * str = [@"http://182.92.5.120/d/file/20150210/lrKXiNVNwfyns/1/mp4/1_1.mp4" stringByReplacingOccurrencesOfString:@":" withString:@""];
NSString * newStr = [str stringByReplacingOccurrencesOfString: @"/" withString:@""];
NSString *cache = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [cache stringByAppendingPathComponent:newStr];
NSFileManager * fielManage = [NSFileManager defaultManager];
if (![fielManage fileExistsAtPath:filePath]) {
[fielManage createFileAtPath:filePath contents:nil attributes:nil];
}
//拿到一個關於文件的handler句柄
self.writeHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
//獲取完整的文件長度
self.sumLength = response.expectedContentLength;
}
只要是有接收數據此方法就會一直執行。
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
self.currentLength = self.currentLength + data.length;
double progress = (double)self.currentLength/self.sumLength;
self.myProgress.progress = progress;
if (self.progressHandle) {sssssss
self.progressHandle(progress);
}
[self.writeHandle seekToEndOfFile];
[self.writeHandle writeData:data];
}
這樣,用NSURLCOnnection封裝的下載器就能夠用了,這是第二種方法。
第三種方法 AFNetworking
仍是直接上代碼,在viewController的h文件中
@interface ViewController : UIViewController
用來顯示進度的進度條
@property (weak, nonatomic) IBOutlet UIProgressView *myProgress;
請求數據對象
@property (nonatomic, strong)AFHTTPRequestOperation * operation;
@end
在viewController的m文件中。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
此方法用來返回須要須要下載的文件的大小
- (unsigned long long)fileSizeForPath:(NSString *)path {
signed long long fileSize = 0;
NSFileManager *fileManager = [NSFileManager new]; // 用defalut線程不安全
NSData * data = [fileManager contentsAtPath:path];
NSInteger length = [data length];
return length;
}
開始下載
- (void)startDownload {
NSString *downloadUrl = @"http://182.92.5.120/d/file/20150210/lrKXiNVNwfyns/1/mp4/1_1.mp4";
NSString *cacheDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *downloadPath = [cacheDirectory stringByAppendingPathComponent:@"mp3"];
NSLog(@"%@",downloadPath);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadUrl]];
//檢查文件是否已經下載了一部分
unsigned long long downloadedBytes = 0;
if ([[NSFileManager defaultManager] fileExistsAtPath:downloadPath]) {
//獲取已下載的文件長度
downloadedBytes = [self fileSizeForPath:downloadPath];
if (downloadedBytes > 0) {
NSMutableURLRequest *mutableURLRequest = [request mutableCopy];
NSString *requestRange = [NSString stringWithFormat:@"bytes=%llu-", downloadedBytes];
[mutableURLRequest setValue:requestRange forHTTPHeaderField:@"Range"];
request = mutableURLRequest;
}
}
//不使用緩存,避免斷點續傳出現問題
[[NSURLCache sharedURLCache] removeCachedResponseForRequest:request];
//下載請求
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
//下載路徑
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:downloadPath append:YES];
//下載進度回調
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
//下載進度
float progress = ((float)totalBytesRead + downloadedBytes) / (totalBytesExpectedToRead + downloadedBytes);
self.myProgress.progress = progress;
NSLog(@"1");
}];
//成功和失敗回調
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[operation start];
self.operation = operation;
}
- (IBAction)Start:(UIButton *)sender {
[self startDownload];
}
- (IBAction)goon:(UIButton *)sender {
[self.operation resume];
}
- (IBAction)Pause:(UIButton *)sender {
[self.operation pause];
}
這樣,斷點續傳就實現了。
這三種方法都是能夠實現斷點續傳的,若是哪裏不對,還望大神批評指正。