网络:断点续传
2016-04-19 14:24
423 查看
#import "ViewController.h" @interface ViewController ()<NSURLConnectionDataDelegate> @property (nonatomic, assign) long long fileSize; // 文件总大小 @property (nonatomic, assign) long long currentLocalSize; // 本地文件的大小 @property (nonatomic, assign) long long currentSize; // 当前接收的文件大小 @property (nonatomic, strong) NSOutputStream *output; // 文件输出流 @property (nonatomic, strong) NSURLConnection *connection; // 下载请求连接 @property (nonatomic, copy) NSString *filePath; // 文件保存的路径 @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } /** 1. 判断本地文件是否存在 2. 获取服务器文件大小 3. 判断本地文件大小跟服务器文件大小的关系 3.1 如果本地文件大小 小于 服务器的 断点续传 文件大小 3.2 如果本地文件大小 等于 服务器的 不需要再次下载 文件大小 3.3 如果本地文件大小 大于 服务器的 先删除本地的文件,再重新下载 0 **/ // 断点续传 下一次下载,从上一次下载到的地方开始 - (IBAction)pause:(id)sender { // 取消下载,只能取消,如果下一次开始下载,又重新开始 [self.connection cancel]; } // 我们在使用别人的软件的时候,点击下载会怎么样? // 提示这个文件是多大,是否下载 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self serverFileSize]; } // HEAD用来请求查看文件大小 - (void)serverFileSize { // NSURL NSString *URLStr =@"http://localhost/01UI基础复习.mp4"; // 百分号转码 URLStr = [URLStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSURL *url = [NSURL URLWithString:URLStr]; // NSURLRequest 获取文件大小,不是使用GET,而是使用HEAD NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [request setHTTPMethod:@"HEAD"]; NSHTTPURLResponse *response; // 获取文件大小,是使用同步 [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL]; // 建议保存的文件名 // NSLog(@"%@",response.suggestedFilename); self.filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename]; self.fileSize = response.expectedContentLength; NSLog(@"%@",self.filePath); // NSLog(@"%lld",fileSize); // 提示用户文件总大下,是否需要下载 // 检查本地文件大小 self.currentLocalSize = [self checkLocalFile]; if (self.currentLocalSize == self.fileSize) { NSLog(@"下载成功"); return; } // 断点续传 0 , 100000 // 下载文件 [self download:url]; } - (long long)checkLocalFile { long long fileSize = 0; // 下载之前先判断本地文件跟服务器文件之前的关系 NSFileManager *manager = [NSFileManager defaultManager]; // 文件属性 NSDictionary *att = [manager attributesOfItemAtPath:self.filePath error:NULL]; // 全到本地文件的大小 long long localFileSize = att.fileSize; if (localFileSize > self.fileSize) { // 删除本地文件 // 删除 [manager removeItemAtPath:self.filePath error:NULL]; fileSize = 0; }else if (localFileSize == self.fileSize) { // 不需要重新下载 fileSize = localFileSize; }else { // 本地文件小于服务器文件 fileSize = localFileSize; } return fileSize; } // 断点续传第三方框架 很少有第三方框架去实现 // ASIHTTP(好几年没更新) - (void)download:(NSURL *)url { dispatch_async(dispatch_get_global_queue(0, 0), ^{ // NSURLRequest 下载文件,从服务器获取的意思 GET NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; NSString *range = [NSString stringWithFormat:@"bytes=%lld-",self.currentLocalSize]; // 设置Range头 [request setValue:range forHTTPHeaderField:@"Range"]; // 开始下载文件, 知道下载的进度 // 代理回调的线程,跟执行这一行代码的线程是同一个 self.connection = [NSURLConnection connectionWithRequest:request delegate:self]; // NSLog(@"开始下载文件"); // 开启运行循环,才能让子线程保持 // 什么时候需要开启运行循环 /** 1. 子线程需要保持,NSTimer 2. 代理回调(代理,block) */ [[NSRunLoop currentRunLoop] run]; }); } #pragma mark - NSURLConnection 代理 /** NSFileHandle 选择写入文件的方式初始化,在写入文件之前先把光标移动文件的最后,写完之后关闭 NSOutputStream 初始化的时候选择拼接文件,再打开流,写入数据(多次),关闭流 */ // 接收到响应 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { // 如果使用了Range头,响应的状态码是206 NSLog(@"接收到响应%@ -- %lld",response,response.expectedContentLength); // NSHTTPURLResponse *httpResp // self.fileSize = response.expectedContentLength; // 文件总大小 self.output = [[NSOutputStream alloc]initToFileAtPath:self.filePath append:YES]; // 在写入编辑文件之前,打开文件 [self.output open]; } // 如果代理方法在主线程中执行 /** 1. 方法会调用很多次 2. 如果主线程没空,不会调用代理(视力滚动的时候,或者在做其他事情),也就是相当于不下载 */ - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { // NSLog(@"接收到数据 %zd",data.length); // 如果需要知道进度,首要要知道文件的总大小,还要接收了多少 self.currentSize += data.length; NSLog(@"%f",(CGFloat)self.currentSize / self.fileSize); // uunt8_t -> NSData // [NSData dataWithBytes:<#(nullable const void *)#> length:<#(NSUInteger)#>] [self.output write:data.bytes maxLength:data.length]; NSLog(@"%@",[NSThread currentThread]); } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSLog(@"下载完成了"); // 关闭文件流 [self.output close]; } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"出错了"); } @end
相关文章推荐
- 网络:取消下载
- 网络:使用多线程下载文件
- [转]使用web.config中的httpHandlers
- 网络:NSOutputStream的使用
- 网络:NSFIleHandle的使用
- 网络:HEAD 的使用
- 网络:文件下载
- javaHTTP请求工具类-使用HttpURLConnection实现
- HttpClient Get/Post方式调用Http接口
- linux 网络编程基础(一)(tcp)
- ios htttp网络请求cookie的读取与写入(NSHTTPCookieStorage)
- LVS在大规模网络环境中的应用
- REST实战——调用百度语音的云服务
- 转自和煦的点滴 » HTML Meta中添加X-UA-Compatible和IE=Edge,chrome=1有什么作用? http://blog.hexu.org/archives/1944.shtm
- TCP/IP的三次握手与四次挥手详解
- HTTP原理
- 简约之美Jodd-http--深入源码理解http协议
- 课程设计之"网络考试系统"(php、Extjs)
- 浅谈HTTP中Get与Post的区别
- Unity5.1 新的网络引擎UNET(十五) Networking 引用--上