(一二六)單線程檔案下載與斷點續傳,一二六單線程

來源:互聯網
上載者:User

(一二六)單線程檔案下載與斷點續傳,一二六單線程

本文討論單線程的檔案下載和斷點續傳,通過從本機伺服器下載一個較大的檔案,實現顯示進度、中途暫停與斷點續傳。

下載過程大致如下:

①通過NSURL建立指向特定的請求,本文中下載的檔案位於網站根目錄的lesson1下的nav.dmg,因此URL應為http://127.0.0.1/lesson1/nav.dmg。

②通過NSURL建立URLRequest,為了能夠更改HTTP要求標頭,實現特定位元組的下載,使用NSMutableURLRequest,然後佈建要求頭的Range範圍,range的主要寫法是bytes=x-y,代表下載x-y的位元組,注意位元組的起始是0。也可以忽略一端,例如x-代表下載x和以後的位元組;而-y表示下載最後y個位元組。

③使用NSURLConnection執行請求,並且設定代理,通過代理方法接收資料。

為了能夠Realtime Compute進度,我們使用一系列變數,記錄下載了的位元組數和總位元組數:

@property (nonatomic, assign) long long totalLength;@property (nonatomic, assign) long long currentLength;

【NSURLConnection的代理方法】

①- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

當出錯時來到這裡。

②- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

這個比較重要,在下載檔案之前會先拿到這個回應標頭,從中可以拿到檔案的大小,在這裡適合做一些初始化工作,例如0B檔案的建立和總大小、當前大小的初始化。

③- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

每當檔案下載完一小塊,就會調用一次,從這裡可以進行檔案拼接,進度更新。

④- (void)connectionDidFinishLoading:(NSURLConnection *)connection

當檔案下載完成時調用這個方法,一般在這裡關閉檔案。

很顯然網路暢通時的調用順序是②->多次③->④。

【檔案的操作】

①通過NSFileManager建立空檔案,用於資料拼接。

// 先建立一個空檔案NSFileManager *mgr = [NSFileManager defaultManager];NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"download.dmg"];[mgr createFileAtPath:path contents:nil attributes:nil];
②為了能夠方便拼接,使用NSFileHandle指向檔案,並且儲存成成員變數。

@property (nonatomic, strong) NSFileHandle *handle;
// 使用檔案控制代碼操作檔案NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:path];_handle = handle;_totalLength = response.expectedContentLength;_currentLength = 0;
③檔案的拼接

通過NSFileHandle的seekToEndOfFile方法可以指向當前檔案尾,然後使用writeData方法向後拼接。

// 下載拼接思路:先建立空檔案,然後一部分一部分的拼接[self.handle seekToEndOfFile];[self.handle writeData:data];
總體來說,思路是一部分一部分的拼出最終檔案。

【斷點續傳】

暫停只能通過結束NSURLConnection實現,connection一旦結束就會失效,只能重新建立。

[self.connection cancel];self.connection = nil;
為了實現下次再從中斷的位置下載,只需要通過_currentLength即可,讓Range為bytes:_currentLength-即可,因為位元組是從0開始的,當前長度為len代表下一個要下載的位元組編號就是len。

請求代碼如下:

NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/lesson1/nav.dmg"];// 通過佈建要求頭range來設定下載資料的範圍NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];NSString *range = [NSString stringWithFormat:@"bytes=%lld-",self.currentLength];[request setValue:range forHTTPHeaderField:@"Range"];self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
另一個注意點是因為新建立了請求,會再去擷取回應標頭,這樣又會用空檔案覆蓋原檔案,重新下載,我們加一個判斷,如果_currentLength≠0,直接返回即可。


下面是完整的代碼,其中downloadBar是進度條,btn用於控制下載開始與暫停,二者均來自storyboard。btn點擊後延時0.5秒開始下載是為了防止點擊後按鈕被阻塞無法到達暫停鍵狀態。

////  ViewController.m//  大檔案下載////  Copyright (c) 2015 soulghost. All rights reserved.//#import "ViewController.h"@interface ViewController () <NSURLConnectionDataDelegate>@property (nonatomic, strong) NSFileHandle *handle;@property (nonatomic, assign) long long totalLength;@property (nonatomic, assign) long long currentLength;@property (weak, nonatomic) IBOutlet UIProgressView *downloadBar;@property (weak, nonatomic) IBOutlet UIButton *btn;@property (nonatomic, strong) NSURLConnection *connection;@end@implementation ViewController- (void)startDownload{        NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/lesson1/nav.dmg"];    // 通過佈建要求頭range來設定下載資料的範圍    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];    NSString *range = [NSString stringWithFormat:@"bytes=%lld-",self.currentLength]; // 從0開始,下到10應該是0-9.下面應該下載10.    [request setValue:range forHTTPHeaderField:@"Range"];    self.connection = [NSURLConnection connectionWithRequest:request delegate:self];    }- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{            }- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{        NSLog(@"下載出錯");    }- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{        if (_currentLength) {        return;    }        // 先建立一個空檔案    NSFileManager *mgr = [NSFileManager defaultManager];    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"download.dmg"];    [mgr createFileAtPath:path contents:nil attributes:nil];        // 使用檔案控制代碼操作檔案    NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:path];    _handle = handle;    _totalLength = response.expectedContentLength;    _currentLength = 0;    self.downloadBar.progress = 0;        }- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{        // 下載拼接思路:先建立空檔案,然後一部分一部分的拼接    [self.handle seekToEndOfFile];    [self.handle writeData:data];        self.currentLength += data.length;    self.downloadBar.progress = (float)self.currentLength / self.totalLength;    NSLog(@"進度:%f",self.downloadBar.progress);;    }- (void)connectionDidFinishLoading:(NSURLConnection *)connection{        [self.handle closeFile];    [self.btn setTitle:@"開始" forState:UIControlStateNormal];    self.currentLength = 0;    }- (IBAction)btnClick:(UIButton *)sender {        if ([sender.titleLabel.text isEqualToString:@"開始"]) {        [sender setTitle:@"暫停" forState:UIControlStateNormal];        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{            [self startDownload];        });    }else{        [sender setTitle:@"開始" forState:UIControlStateNormal];        [self.connection cancel];        self.connection = nil;    }        }@end

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.