断点续传功能

本文详细介绍了在iOS应用中优化下载性能的方法,包括使用缓冲Data存储下载数据,当缓冲数据超过500kb时将其写入文件以节约内存。同时,阐述了断点续传的实现思路,通过HTTP协议的请求头设置Range参数,实现暂停与继续下载的功能,确保下载过程的连续性和高效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#define kReceiveTotal @"receiveTotal"

#define kTotal @"total"


@interface ViewController ()


@end


/**

 一、下载的性能优化

 1. 使用一个缓冲Data存储下载的数据,当缓冲的数据>500kb,将此缓冲数据写入文件,并且清除缓冲数据,以节约内存

 

 二、断点续传的实现思路:

 1. 暂停的时候,记录下载的暂停位置

 

 2. 继续下载时,设置下载的起始位置

 

     http协议的请求头的设置:

     Range : bytes=0-499   表示头500个字节

     Range : bytes=500-999 表示第二个500字节

     Range : bytes=-500    表示最后500个字节

     Range : bytes=500-    表示500字节以后的范围

     Range : bytes=0-0,-1  第一个和最后一个字节

 

 3. 续传写入文件时,总是从文件末尾追加写入文件

 


 */


//缓冲目录  1.png

//目标目录  1.png


@implementation ViewController {

    

    //2.下载数据的总大小

    double total;

    //3.接受数据的大小

    double receiveTotal;

    

    //4.缓冲数据

    NSMutableData *_bufferData;

    //5.下载路径(缓冲目录)

    NSString *_filePath;

    

    NSURLConnection *_connection;

}


- (void)viewDidLoad {

    [super viewDidLoad];

    

    //取得下载大小的数据

    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

    receiveTotal = [[userDefaults objectForKey:kReceiveTotal] doubleValue];

    total = [[userDefaults objectForKey:kTotal] doubleValue];

    

    //显示上次下载的进度

    if (total > 0) {

        CGFloat progress = receiveTotal/total;

        _progressView.progress = progress;

        _progreeLabel.text = [NSString stringWithFormat:@"%.2f%%",progress*100];

    }

    

}


- (IBAction)startAction:(id)sender {

    NSURL *url = [NSURL URLWithString:@"http://img31.mtime.cn/pi/2013/03/13/115558.26463213_1280X720.jpg"];

    //默认就是GET请求

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    //设置不缓存

    [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];

    

#warning 断点续传添加的代码

    if (receiveTotal > 0) {

        //设置继续下载的位置

        NSString *value = [NSString stringWithFormat:@"bytes=%d-",(int)receiveTotal];

        [request setValue:value forHTTPHeaderField:@"Range"];

        

        NSLog(@"继续下载:%@",request.allHTTPHeaderFields);

    }

    

    //发送异步请求

    _connection = [NSURLConnection connectionWithRequest:request delegate:self];

    

    

    //创建文件

    //取得字符串的URL

    NSString *urlstring = url.absoluteString;

    //取得URL的最后一部分

    NSString *filename = [urlstring lastPathComponent];

    

    //文件路径

    

    

    _filePath = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/temp/%@",filename];

    //判断文件是否存在,如果不存在,再创建

    if (![[NSFileManager defaultManager] fileExistsAtPath:_filePath]) {

        

        //1.创建文件夹

        NSString *dirPath = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/temp"];;

        //2.创建文件

        [[NSFileManager defaultManager] createFileAtPath:_filePath contents:nil attributes:nil];

    }

    

}


//暂停下载

- (IBAction)pauseAction:(id)sender {

    

    //1.取消下载连接

    [_connection cancel];

    _connection = nil;

    

    //2.将缓冲数据写入文件

    [self appendFileData:_bufferData];

    

    //3.本地保存下载的位置

#warning 后续在添加

    NSUserDefaults *userDetaults = [NSUserDefaults standardUserDefaults];

    //保存已接受的大小

    [userDetaults setObject:@(receiveTotal) forKey:kReceiveTotal];

    [userDetaults setObject:@(total) forKey:kTotal];

    //将数据同步写入文件

    [userDetaults synchronize];

}


#pragma mark - NSURLConnection delegate

//1.服务响应

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {

    

    _bufferData = [[NSMutableData alloc] init];

    

    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;

    

    //判断总大小是否为0,如果是0,说明从起始位置下载,需要获取文件大总大小

    if (total == 0) {

        //取得所有的响应头

        NSDictionary *fields = [httpResponse allHeaderFields];

        

        //取得数据的总大小

        NSNumber *length = [fields objectForKey:@"Content-Length"];

        

        total = [length doubleValue];

    }

    

    NSLog(@"%@",httpResponse.allHeaderFields);

    

}


//2.数据的传输

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

    

    //1.接受传输的数据

    [_bufferData appendData:data];

    

    //2.接受的数据大小/总大小  = 进度

    receiveTotal += data.length;

    double progress = receiveTotal / total;

    

    //3.刷新UI

    _progressView.progress = progress;

    _progreeLabel.text = [NSString stringWithFormat:@"%.2f%%",progress*100];

    

//    NSLog(@"接受了%d字节数据",data.length);

    NSLog(@"已接受了%d字节数据",(int)receiveTotal);

    

    //4.判断缓冲的数据大小是否>10kb

    if (_bufferData.length > 10*1000) {

        

        [self appendFileData:_bufferData];

        

        [_bufferData setData:nil];

    }

    

    

}


//3.数据传输完成

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {


    //将最后一个缓冲区数据写入文件

    if (_bufferData.length < 10*1000) {

        

        [self appendFileData:_bufferData];

        [_bufferData setData:nil];

    }

    

    _progreeLabel.text = @"下载完成";

    

    //将下载完成的文件从缓冲目录剪切到目标目录

    NSFileManager *fileManager = [NSFileManager defaultManager];

    

    NSString *fileName = [_filePath lastPathComponent];

    NSString *targetFile = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/%@",fileName];

    

    //判断目标文件是否存在,如果存在,就删除掉

    if ([fileManager fileExistsAtPath:targetFile]) {

        [fileManager removeItemAtPath:targetFile error:nil];

    }

    

    //剪切文件,注意:剪切不能将已存在的文件覆盖

    [fileManager moveItemAtPath:_filePath toPath:targetFile error:nil];

    

    

    //下载完成之后,将本地保存的下载位置清零

    NSUserDefaults *userDefatuls = [NSUserDefaults standardUserDefaults];

    [userDefatuls setObject:@(0) forKey:kReceiveTotal];

    [userDefatuls setObject:@(0) forKey:kTotal];

    //将数据同步写入文件

    [userDefatuls synchronize];

    

    receiveTotal = 0;

    total = 0;

}


//将数据追加到文件末尾

- (void)appendFileData:(NSData *)appData {

    

    if (appData.length == 0 || _filePath.length == 0) {

        return;

    }

    

    // 使用NSFileHandle写文件,此文件必须已经创建,NSFileHandle是不会创建文件的

    NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:_filePath];

    //将文件的写入点,定位到文件的末尾

    [fileHandle seekToEndOfFile];

    [fileHandle writeData:appData];

    

    [fileHandle closeFile];

    

}


@end


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值