iOS网络-通过NSURLConnection文件下载,断点下载,输出流下载

小文件下载
NSURLConnection-delegate实现,可以监听到下载的进度,但是还是无法解决内存飙升的问题,所以仅限小文件下载
 1 @interface ViewController ()<NSURLConnectionDataDelegate>
 2 @property (weak, nonatomic) IBOutlet UIProgressView *progressView;
 3 /** 接收数据的data */
 4 @property (nonatomic, strong) NSMutableData *fileData; 6 /*文件名称 */
 7 @property (nonatomic, strong) NSString *fileName;
 8 @property (nonatomic, assign) NSInteger totalSize;
 9 @end
10 @implementation ViewController
11 -(NSMutableData *)fileData
12 {
13     if (_fileData == nil) {
14         _fileData = [NSMutableData data];
15     }
16     return _fileData;
17 }
18 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
19 {
20     //1.确定URL
21     NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
22     //2.创建请求对象
23     NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
24     //3.设置代理,发送请求
25     [NSURLConnection connectionWithRequest:request delegate:self];
26 }
27 #pragma mark - NSURLConnectionDataDelegate
28 -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
29 {
30     //suggestedFilename:服务器端推荐的名称,其实就是url的最后一个节点
31     self.fileName = response.suggestedFilename;
32     //expectedContentLength:获得文件总大小
33 
34     self.totalSize = response.expectedContentLength;
35 }
36 -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
37 {
38     //拼接数据
39     [self.fileData appendData:data];
40     //计算文件的下载进度== 已经下载的大小/文件的总大小
41     NSLog(@"%f",1.0 * self.fileData.length /self.totalSize);
42     //进度UI43     self.progressView.progress = 1.0 * self.fileData.length /self.totalSize;
44 }
45 -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
46 {
47 }
48 -(void)connectionDidFinishLoading:(NSURLConnection *)connection
49 {
50     //写数据到磁盘
51     NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
52     //拼接全路径
53     NSString *fullPath = [caches stringByAppendingPathComponent:self.fileName];
54     //写沙盒
55     [self.fileData writeToFile:fullPath atomically:YES];
56 }
57 @end
大文件下载 
NSURLConnection-delegate实现, 实现思路: 边接收数据边写文件以解决内存越来越大的问题
@interface ViewController ()<NSURLConnectionDataDelegate>
@property (weak, nonatomic) IBOutlet UIProgressView *progressView;

/*文件名称 */
@property (nonatomic, strong) NSString *fileName;
/*文件的总大小*/
@property (nonatomic, assign) NSInteger totalSize;
/*已经下载的文件大小*/
@property (nonatomic, assign) NSInteger currentSize;
/** 文件句柄 */
@property (nonatomic, strong) NSFileHandle *handle;
@end

@implementation ViewController
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
     //1.确定URL
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
    //2.创建请求对象
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
    //3.设置代理,发送请求
    [NSURLConnection connectionWithRequest:request delegate:self];

}
#pragma mark - NSURLConnectionDataDelegate
//接收到服务器的响应
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    //1.获得caches目录
    NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    //2.拼接全路径
    NSString *fullPath = [caches stringByAppendingPathComponent:response.suggestedFilename];
    //3.获得本次请求的文件数据大小(期望大小)
    self.totalSize = response.expectedContentLength;
    //4.新建一个空的文件
    /*
     第一个参数:文件的目录
     第二个参数:文件的内容
     第三个参数:文件的属性
     */
    [[NSFileManager defaultManager]createFileAtPath:fullPath contents:nil attributes:nil];
    //5.创建文件句柄
    NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:fullPath];
    self.handle = handle;
}

//接收到服务器返回的数据
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    //1.移动文件句柄到文件的末尾
    [self.handle seekToEndOfFile];
    //2.写数据到磁盘
    [self.handle writeData:data];
    //3.计算文件的下载进度== 已经下载的大小/文件的总大小
    self.currentSize +=data.length;
    NSLog(@"%f",1.0 * self.currentSize /self.totalSize);
    //4.进度UI
    self.progressView.progress = 1.0 * self.currentSize /self.totalSize;
}
//请求完成
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    //释放文件句柄
    [self.handle closeFile];
    self.handle = nil;
}
@end
大文件断点下载
    实现思路: 设置请求头NSFileHandle
     在下载文件的时候不再是整块的从头开始下载,而是看当前文件已经下载到哪个地方,然后从该地方接着往后面下载。可以通过在请求对象中设置请求头实现。
  1.设置请求头,在开始下载的时候设置
    //2.创建请求对象 可变的
       NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    //2.1 设置下载文件的某一部分
    // 只要设置HTTP请求头的Range属性, 就可以实现从指定位置开始下载
    /*
     表示头500个字节:Range: bytes=0-499
     表示第二个500字节:Range: bytes=500-999
     表示最后500个字节:Range: bytes=-500
     表示500字节以后的范围:Range: bytes=500-
     */
    NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentLength];
    [request setValue:range forHTTPHeaderField:@"Range"];

   2.注意点(下载进度并判断是否需要重新创建文件)

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response接收到服务器的响应的方法中代码改动:

  //注意点:response.expectedContentLength获得是本次请求要下载的文件的大小(并非是完整的文件的大小)
//
文件的总大小 == 本次要下载的文件大小 + 已经下载的文件的大小 self.totalLength = response.expectedContentLength + self.currentLength; // 判断当前是否已经下载过,如果当前文件已经存在,那么直接返回,不然新下载的大小会覆盖原来文件,导致前面文件丢失 if (self.currentLength >0) { return; }
大文件输出流下载
使用输出流也可以实现和NSFileHandle相同的功能
    //1.创建一个数据输出流
    /*
     第一个参数:二进制的流数据要写入到哪里
     第二个参数:采用什么样的方式写入流数据,如果YES则表示追加,如果是NO则表示覆盖
     */
    NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:fullPath append:YES];

    //只要调用了该方法就会往文件中写数据
    //如果文件不存在,那么会自动的创建一个
    [stream open];
    self.stream = stream;

    //2.当接收到数据的时候写数据
    //使用输出流写数据
    /*
     第一个参数:要写入的二进制数据
     第二个参数:要写入的数据的大小
     */
    [self.stream write:data.bytes maxLength:data.length];

    //3.当文件下载完毕的时候关闭输出流
    //关闭输出流
    [self.stream close];
    self.stream = nil;
原文地址:https://www.cnblogs.com/liugengqun/p/5136995.html