美文网首页
下载文件断点续传(NSURLConnection)

下载文件断点续传(NSURLConnection)

作者: 玉松 | 来源:发表于2016-07-14 10:41 被阅读64次

    @interface FileDownloader() <NSURLConnectionDataDelegate>

    //下载文件的总大小 
    @property (nonatomic, assign) long long            expectedContentLength;
    // 当前已经下载的文件大小 
    @property (nonatomic, assign) long long fileSize;
     // 文件保存目标路径 
    @property (nonatomic, copy) NSString *targetPath;
    @property (nonatomic, strong) NSOutputStream   *fileStream;
    

    @end

    @implementation CZFileDownloader
    /**
    加载数据
    不要在主方法中写碎代码!
    */

    - (void)downloadWithURL:(NSURL *)url {
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        // 1. 检查服务器上的文件大小(大小和文件名)
        [self loadFileInfoWithURL:url];
        NSLog(@"%@ %lld", self.targetPath, self.expectedContentLength);
        
        // 2. 检查本地文件的信息(大小)
        long long fileSize = [self checkLocalFile];
        NSLog(@"本地文件大小 %lld", fileSize);
        
        if (fileSize == self.expectedContentLength) {
            NSLog(@"文件下载已经完成!");
            return;
        }
        
        // 3. 根据本地文件大小开始下载文件
        [self downloadWithURL:url offset:fileSize];
    });}
    

    // MARK: - 根据本地文件的大小下载网络文件

    - (void)downloadWithURL:(NSURL *)url offset:(long long)offset {
    
    // 0. 记录当前文件大小
    self.fileSize = offset;
    
    // 1. 设置下载范围的 request
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:1 timeoutInterval:CZTimeOut];
    
    // 指定下载的范围
    NSString *rangeString = [NSString stringWithFormat:@"bytes=%lld-", offset];
    [request setValue:rangeString forHTTPHeaderField:@"Range"];
    
    // 2. 启动网络连接
    // For the connection to work correctly, the calling thread’s run loop must be operating in the default run loop mode.
    // 为了保证连接的工作正常,调用线程的运行循环必须以默认运行循环模式工作!
    NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
    
    [conn start];
    
    /**
     开启运行循环,而且是死循环!
     等到网络下载完全结束后,运行循环会自动关闭!
     */
    CFRunLoopRun();
    
    NSLog(@"下载了吗? %@", [NSThread currentThread]);
    

    }
    // MARK: - 检查本地文件的大小信息

    -(long long)checkLocalFile {
    
    // 1. 判断文件是否存在
    NSFileManager *manager = [NSFileManager defaultManager];
    
    long long fileSize = 0;
    
    if ([manager fileExistsAtPath:self.targetPath]) {
        NSLog(@"文件存在");
        
        // 2. 检查本地文件大小
        NSDictionary *attributes = [manager attributesOfItemAtPath:self.targetPath error:NULL];
        // 1> 通过字典的键值直接取得文件大小
        //     self.fileSize = [attributes[NSFileSize] longLongValue];
        // 2> 通过字典的分类方法获取文件大小
        fileSize = [attributes fileSize];
    }
    
    /**
     1> 文件比服务器上的要小,从文件大小开始下载,fileSize 是实际大小
     2> 文件比服务器上的要大,重新下载=>fileSize = 0,删除文件
     3> 文件不存在,直接下载 fileSize = 0
     */
    if (fileSize > self.expectedContentLength) {
        [manager removeItemAtPath:self.targetPath error:NULL];
        fileSize = 0;
    }
    
    return fileSize;
    

    }

    // MARK: - 加载服务器的文件信息

    - (void)loadFileInfoWithURL:(NSURL *)url {
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:1 timeoutInterval:CZTimeOut];
    request.HTTPMethod = @"HEAD";
    
    // 使用同步的 HEAD 方法获取服务器文件信息
    NSURLResponse *response = nil;
    [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
    
    // 记录总大小
    self.expectedContentLength = response.expectedContentLength;
    // 记录目标文件路径,将下载文件保存在 tmp 目录下
    self.targetPath = [NSTemporaryDirectory() stringByAppendingPathComponent:response.suggestedFilename];
    

    }

    MARK:NSURLConnectionDataDelegate

       // 1. 接收到服务器的响应
    -(void)connection:(NSURLConnection**)connectiondidReceiveResponse:(NSURLResponse* *)response {
    NSLog(@"%@", response);
    // 创建并打开文件流
    self.fileStream = [[NSOutputStream alloc] initToFileAtPath:self.targetPath append:YES];
    
    [self.fileStream open];
    

    }

    // 2. 接收到二进制数据(可能会执行多次)

    -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    // 累加大小
    self.fileSize += data.length;
    // 计算进度 (小 long long / 大 long long) = 0 long long
    float progress = (float)self.fileSize / self.expectedContentLength;
    NSLog(@"===> %f %@", progress, [NSThread currentThread]);
    
    // 拼接数据流
    [self.fileStream write:data.bytes maxLength:data.length];
    

    }

    // 3. 所有数据接收完成

    - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSLog(@"完成");
    
    // 关闭流
    [self.fileStream close];}
    

    // 4. 错误处理

     - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"%@", error);
    
    // 关闭流
    [self.fileStream close];}
    

    @end

    相关文章

      网友评论

          本文标题:下载文件断点续传(NSURLConnection)

          本文链接:https://www.haomeiwen.com/subject/vneejttx.html