iOS網絡之03文件下載

一,小文件下載:

1,NSData直接下載:(內部默認發送GET請求,但是只會在子線程,that‘s bad)

注意:這兩種方法如果在下載過程中斷網終止下載,那么重新下載需要從零開始,所以不適合大文件
不能監聽下載進度

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSURL *url = [NSURL URLWithString:@"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png"];
    //下載到內存中
    NSData *data = [NSData dataWithContentsOfURL:url];
    NSLog(@"%lu",(unsigned long)data.length);
});

2,向服務器發送請求下載:(手動發送GET請求)

NSURL *url = [NSURL URLWithString:@"http://192.168.1.100:8080/MJServer/resources/images/minion_01.png"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
    NSLog(@"%lu",data.length);
}];
二,單線程大文件下載:(可以監聽下載進度)

1,非斷點下載單線程下載,如下:

主要的API:(NSURLConnection異步方法,會自動開啟異步線程,設置代理后可以通過代理方法監聽事件并作出相應的處理)
[NSURLConnection connectionWithRequest:request delegate:self];

如下:

//1,發送請求
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSURL *url = [NSURL URLWithString:@"http://w.x.baidu.com/alading/anquan_soft_down_all/14247"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [NSURLConnection connectionWithRequest:request delegate:self];
}
//2,如果出錯來到這里
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    NSLog(@"didFailWithError");
}
//3,接受到響應,只會調用一次
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString *file = [cachesPath stringByAppendingPathComponent:@"QQ影音.exe"];
    
    NSFileManager *mgr = [NSFileManager defaultManager];
    [mgr createFileAtPath:file contents:nil attributes:nil];
    
    NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:file];
    self.handle = handle;
    self.totalLength = response.expectedContentLength;
}
//4,開始接受數據,調用多次,這里創建句柄對象對數據分段存儲(如果只有一個子線程可以用下面seekToEndOfFile方法,如果是多線程那么需要先創建一個等同整個原始文件大小的文件,然后在用[self.handle seekToFileOffset:offset]方法存儲數據)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    [self.handle seekToEndOfFile];
    [self.handle writeData:data];
    self.currentLength += data.length;
    NSLog(@"下載進度是:%f",(double)self.currentLength/self.totalLength);
}
//5,存儲完畢后關閉句柄,調用一次
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    [self.handle closeFile];
    self.handle = nil;
    self.currentLength = 0;
    self.totalLength = 0;
}
三,單線程的斷點下載:
  • 單線程斷點下載.gif
- (IBAction)btnClicked:(UIButton *)sender {
    sender.selected = !sender.isSelected;
    
    if (sender.selected) {//下載或者重新下載
        //注意:這里的請求需要改成可變請求,因為后面要設置請求的下載位置
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://w.x.baidu.com/alading/anquan_soft_down_all/14247"]];
        //需要一個全局的request以方便我暫停之后重新下載的時候設置下載的位置
        self.request = request;
        
        //設置請求頭,從當前位置下載
        NSString *range = [NSString stringWithFormat:@"bytes=%lld-",self.currentLength];
        [request setValue:range forHTTPHeaderField:@"Range"];
        
        //單線程下載(非斷點下載)
        self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
    }else{//按鈕未被選中,暫停下載
        //NSURLConnection不支持暫停,只能取消,重新開始任務時候從當前位置下載等同于取消操作
        [self.connection cancel];
        self.connection = nil;
    }
}

//如果請求失敗調用
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    NSLog(@"didFailWithError---%@",error);
}

//建立連接獲得相應的時候調用,只會調用一次,這里因為要實現斷點續傳,所以這個方法會調用多次,每次暫停一次就會重新調用一次
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    NSLog(@"didReceiveResponse--接收到響應,開始下載--%@",response);
    //下面這句非常重要,如果沒有這一句,會重新創建新的文件,會出問題
    if (self.currentLength) return;
    
    NSString *filePath = @"/users/feng/desktop/QQ影音.exe";
    NSFileManager *manager = [NSFileManager defaultManager];
    [manager createFileAtPath:filePath contents:nil attributes:nil];
    
    //建立句柄以方便后面每接受到一段數據可以插入到文件后面
    NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:filePath];
    self.handle = handle;
    //統計該數據的總大小
    self.totalLength = response.expectedContentLength;
}

//每次獲取一段數據調用過一次,會調用多次
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    //    NSLog(@"didReceiveData----%@",data);
    NSLog(@"didReceiveData------");
    [self.handle seekToEndOfFile];
    [self.handle writeData:data];
    
    self.currentLength += data.length;
    self.progressView.progress = (double)self.currentLength/self.totalLength;
}

//完成下載的時候調用一次
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    NSLog(@"connectionDidFinishLoading");
    
    [self.handle closeFile];
    self.handle = nil;
    
    self.totalLength = 0;
    self.currentLength = 0;
    self.btn.selected = NO;
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容