一,小文件下載:
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;
}