關於斷點續傳的那些事

      最近在研究視頻下載的內容,下載的時候須要實現斷點續傳,上網查了不少資料,大部分都是程序運行時能夠實現斷點續傳,可是程序退出後,再次進入又得從頭開始,因此研究了好幾天,總結了如下幾種可以實現程序從新運行時斷點續傳的方法,廢話很少說,進入正題。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];

}

 這樣,斷點續傳就實現了。

這三種方法都是能夠實現斷點續傳的,若是哪裏不對,還望大神批評指正。

相關文章
相關標籤/搜索