iOS 开发-文件下载原理

  • 文件上传
  1. 创建文件上传类FileDownload.h

    //
    //  FileDownload.h
    //  01.文件下载
    //
    //  Created by wyh on 15-1-29.
    //  Copyright (c) 2015年 itcast. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface FileDownload : NSObject
    
    - (void)downloadFileWithURL:(NSURL *)url completion:(void (^)(UIImage *image))completion;
    
    @end
  2. 创建文件上传类FileDownload.m

    //
    //  FileDownload.m
    //  01.文件下载
    //
    //  Created by wyh on 15-1-29.
    //  Copyright (c) 2015年 itcast. All rights reserved.
    //
    
    #import "FileDownload.h"
    #import "NSString+Password.h"
    
    #define kTimeOut        2.0f
    // 每次下载的字节数
    #define kBytesPerTimes  20250
    
    @interface FileDownload()
    @property (nonatomic, strong) NSString *cacheFile;
    @property (nonatomic, strong) UIImage *cacheImage;
    @end
    
    @implementation FileDownload
    /**
     为了保证开发的简单,所有方法都不使用多线程,所有的注意力都保持在文件下载上
    
     在开发中如果碰到比较绕的计算问题时,建议:
     1> 测试数据不要太大
     2> 测试数据的数值变化,能够用笔算计算出准确的数值
     3> 编写代码对照测试
    
     */
    //- (NSString *)cacheFile
    //{
    //    if (!_cacheFile) {
    //        NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
    //        _cacheFile = [cacheDir stringByAppendingPathComponent:@"123.png"];
    //    }
    //    return _cacheFile;
    //}
    - (UIImage *)cacheImage
    {
        if (!_cacheImage) {
            _cacheImage = [UIImage imageWithContentsOfFile:self.cacheFile];
        }
        return _cacheImage;
    }
    
    - (void)setCacheFile:(NSString *)urlStr
    {
        NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
        urlStr = [urlStr MD5];
    
        _cacheFile = [cacheDir stringByAppendingPathComponent:urlStr];
    }
    
    - (void)downloadFileWithURL:(NSURL *)url completion:(void (^)(UIImage *image))completion
    {
        // GCD中的串行队列异步方法
        dispatch_queue_t q = dispatch_queue_create("cn.itcast.download", DISPATCH_QUEUE_SERIAL);
    
        dispatch_async(q, ^{
            NSLog(@"%@", [NSThread currentThread]);
    
            // 把对URL进行MD5加密之后的结果当成文件名
            self.cacheFile = [url absoluteString];
    
            // 1. 从网络下载文件,需要知道这个文件的大小
            long long fileSize = [self fileSizeWithURL:url];
            // 计算本地缓存文件大小
            long long cacheFileSize = [self localFileSize];
    
            if (cacheFileSize == fileSize) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    completion(self.cacheImage);
                });
                NSLog(@"文件已经存在");
                return;
            }
    
            // 2. 确定每个数据包的大小
            long long fromB = 0;
            long long toB = 0;
            // 计算起始和结束的字节数
            while (fileSize > kBytesPerTimes) {
                // 20480 + 20480
                //
                toB = fromB + kBytesPerTimes - 1;
    
                // 3. 分段下载文件
                [self downloadDataWithURL:url fromB:fromB toB:toB];
    
                fileSize -= kBytesPerTimes;
                fromB += kBytesPerTimes;
            }
            [self downloadDataWithURL:url fromB:fromB toB:fromB + fileSize - 1];
    
            dispatch_async(dispatch_get_main_queue(), ^{
                completion(self.cacheImage);
            });
        });
    }
    
    #pragma mark 下载指定字节范围的数据包
    /**
     NSURLRequestUseProtocolCachePolicy = 0,        // 默认的缓存策略,内存缓存
    
     NSURLRequestReloadIgnoringLocalCacheData = 1,  // 忽略本地的内存缓存
     NSURLRequestReloadIgnoringCacheData
     */
    - (void)downloadDataWithURL:(NSURL *)url fromB:(long long)fromB toB:(long long)toB
    {
        NSLog(@"数据包:%@", [NSThread currentThread]);
    
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:kTimeOut];
    
        // 指定请求中所要GET的字节范围
        NSString *range = [NSString stringWithFormat:@"Bytes=%lld-%lld", fromB, toB];
        [request setValue:range forHTTPHeaderField:@"Range"];
        NSLog(@"%@", range);
    
        NSURLResponse *response = nil;
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
    
        // 写入文件,覆盖文件不会追加
    //    [data writeToFile:@"/Users/aplle/Desktop/1.png" atomically:YES];
        [self appendData:data];
    
        NSLog(@"%@", response);
    }
    
    #pragma mark - 读取本地缓存文件大小
    - (long long)localFileSize
    {
        // 读取本地文件信息
        NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.cacheFile error:NULL];
        NSLog(@"%lld", [dict[NSFileSize] longLongValue]);
    
        return [dict[NSFileSize] longLongValue];
    }
    
    #pragma mark - 追加数据到文件
    - (void)appendData:(NSData *)data
    {
        // 判断文件是否存在
        NSFileHandle *fp = [NSFileHandle fileHandleForWritingAtPath:self.cacheFile];
        // 如果文件不存在创建文件
        if (!fp) {
            [data writeToFile:self.cacheFile atomically:YES];
        } else {
            // 如果文件已经存在追加文件
            // 1> 移动到文件末尾
            [fp seekToEndOfFile];
            // 2> 追加数据
            [fp writeData:data];
            // 3> 写入文件
            [fp closeFile];
        }
    }
    
    #pragma mark - 获取网络文件大小
    - (long long)fileSizeWithURL:(NSURL *)url
    {
        // 默认是GET
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:kTimeOut];
    
        // HEAD 头,只是返回文件资源的信息,不返回具体是数据
        // 如果要获取资源的MIMEType,也必须用HEAD,否则,数据会被重复下载两次
        request.HTTPMethod = @"HEAD";
    
        // 使用同步方法获取文件大小
        NSURLResponse *response = nil;
    
        [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
    
        // expectedContentLength文件在网络上的大小
        NSLog(@"%lld", response.expectedContentLength);
    
        return response.expectedContentLength;
    }
    
    @end
  3. 控制器中调用

    //
    //  ViewController.m
    //  01.文件下载
    //
    //  Created by wyh on 15-1-29.
    //  Copyright (c) 2015年 itcast. All rights reserved.
    //
    
    #import "ViewController.h"
    #warning 包含FileDownload.h文件
    #import "FileDownload.h"
    
    @interface ViewController ()
    @property (nonatomic, strong) FileDownload *download;
    @property (weak, nonatomic) IBOutlet UIImageView *imageView;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    #warning 创建FileDownload对象,并调用方法downloadFileWithURL:
        self.download = [[FileDownload alloc] init];
        [self.download downloadFileWithURL:[NSURL URLWithString:@"http://localhost/itcast/images/head4.png"] completion:^(UIImage *image) {
    
            self.imageView.image = image;
        }];
    }
    
    @end
时间: 2024-10-12 22:47:44

iOS 开发-文件下载原理的相关文章

iOS开发·runtime原理新葡京网站开发与实践: 基本知识篇

运行时新葡京网站开发haozbbs.comQ1446595067 1.1 基本概念: 运行时 Runtime 的概念 Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的.比如: 以上你可能看不出它的价值,但是我们需要了解的是 Objective-C 是一门动态语言,它会将一些工作放在代码运行时才处理而并非编译时.也就是说,有很多类和成员变量在我们编译的时是不知道的,而在运行时,我们所编写的代码会转换成完整的

iOS开发-UIScrollView原理

转载:http://www.cnblogs.com/xiaofeixiang/p/5144256.html UIScrollView 在开发中是不可避免,关于UIScrollView都有自己一定的理解.滚动视图有两个需要理解的属性,frame和bounds,frame是定义了视 图在窗口的大小和位置,bounds表示视图在其自身坐标系中的位置和大小,frame影响视图在窗口位置,bounds会影响子视图的位置. 先来看一张图片: 我们用一个父View将整个窗口铺满,然后添加子视图: UIView

读&lt;iOS开发进阶&gt;有感

花了两天时间, 零零散散看完了这本书.总的来说, 比较失望吧. 花点时间记录下. 第一次看到这本书, 是在看唐巧大神博客的时候看到的  ---------->  <iOS开发进阶>即将出版 那时候, 就被吸引住了.原因不外乎如下三点: 作者: 唐巧大神写的书, 怎么能错过 内容: 开发进阶, 学习了iOS有一段时间, 确实比较期待这类的书籍 封面: 简约大气, 很喜欢. 然后就一直等出版, 本来说12月底就能出版, 然后一直拖, 当当要到1月20号左右才正式出售, 现在都是预售阶段..

《iOS开发进阶》书籍目录

第一部分:iOS开发工具 第二部分:iOS开发实践 第10章 理解内存管理 10.1 引用计数 10.1.1 什么是引用计数,原理是什么 10.1.2 我们为什么需要引用计数 10.1.3 不要向已经释放的对象发送消息 10.1.4 循环引用(reference cycles)问题 10.1.5 使用Xcode检测循环引用 10.2 使用ARC 10.2.1 Automatic Reference Count 10.2.2 Core Foundation对象的内存管理 第11章 掌握GCD 11

iOS开发 -文件下载(4 暂停和恢复)

iOS开发网络篇—文件下载(四·暂停和恢复) 一.Range简单说明 通过设置请求头Range可以指定每次从网路下载数据包的大小 Range示例 bytes=0-499 从0到499的头500个字节 bytes=500-999 从500到999的第二个500字节 bytes=500- 从500字节以后的所有字节 bytes=-500 最后500个字节 bytes=500-599,800-899 同时指定几个范围 Range小结 - 用于分隔 前面的数字表示起始字节数 后面的数组表示截止字节数,没

iOS开发 -文件下载(6压缩和解压)

iOS开发网络篇—文件下载(六·压缩和解压) 一.完成文件下载 需求:完成文件下载 1.在本地服务器中,添加一个图片的压缩文件. 2.代码示例: 文件下载器代码: 头文件 1 // 2 // YYfileDownloader.h 3 // 01-文件的下载(不合理) 4 // 5 // Created by apple on 14-7-1. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <Founda

iOS开发之网络编程--使用NSURLConnection实现大文件下载

主要思路(实现下载数据分段写入缓存中) 1.使用NSURLConnectionDataDelegate以及代理方法.2.在成功获取响应的代理方法中,获得沙盒全路径,并在该路径下创建空文件和文件句柄.3.在获取data的代理方法中,先设置句柄在沙盒全路径文件末尾,然后通过句柄写入data数据.4.在文件下载完的代理方法中,关闭句柄同时设置句柄引用为nil释放句柄和指针. 使用句柄的思路图(红色的箭头表示句柄,灰色的箭头表示移动的路径): 代码关键词: 类:NSFileHandle的方法 1.fil

iOS开发 -文件下载(5 下载功能的封装)

iOS开发网络篇—文件下载(五·下载功能的封装) 一.简单说明 在前面几篇文章介绍下载代码的基础上,此文分析对下载功能进行封装. 通过之前的代码,我们发现仅仅是下载一个文件就需要写很长的代码,那么如果要下载多个文件,就需要写多份代码.在这里,我们把下载一个文件的代码进行封装.控制器只需要知道,下载哪个文件,下载到哪个路径就可以了. 在对下载的功能进行封装后,添加一个文件下载器,一个文件下载器只下载一个文件,封装后如果要下载多个文件的话,那么只需要创建多个文件下载器对象就可以进行控制和下载了. 二

iOS开发 -文件下载(1不合理)

iOS开发网络篇—文件下载(一·不合理) 一.小文件下载 如果文件比较小,下载方式会比较多 直接用NSData的+ (id)dataWithContentsOfURL:(NSURL *)url; 利?NSURLConnection发送一个HTTP请求去下载 如果是下载图片,还可以利用SDWebImage框架 二.沙盒 1.在finder中,系统的一些文件(资源库)是隐藏的,可以通过在终端运行下图的代码,显示隐藏的文件. 显示隐藏系统文件: defaults write com.apple.fin