文件的断点续传(即下载),同时保存到指定目录

https://github.com/potato512/SYDemo_SYDownloadTask

在网络处理中,特别是对文件进行下载操作时,可能会出现网络异常导致的下载中断,或是设备电池没有电时的中断,又或是人为的中断。为了避免从头开始进行下载,即从下载中断点继续开始下载,这时候我们就需要使用到断点续传技术。

在iOS中,我们可以使用NSURLSession,NSURLSessionDownloadTask进行继点续传的处理。

在实现过程中有两点需要注意:

1、断点续传过程中,中断时要记录中断时的信息,以便重新进行下载时可以从中断点开始下载;

2、断点续传结束后,需要将文件保存在指定目录中,以便于后续的操作;

具体实现代码如下:

1、封装断点续传下载类

// .h文件
#import <Foundation/Foundation.h>

@interface SYDownloadTask : NSObject

/**
 *  下载区域
 */
@property (nonatomic, strong, readonly) NSData *resumeData;

/**
 *  开始下载
 *
 *  @param url      下载地址
 *  @param complete 下载回调
 */
- (void)downloadStartWithURL:(NSString *)url complete:(void (^)(BOOL isFinish, NSString *filePath, long long downloadBytes, long long totalBytes))complete;

/**
 *  继续下载
 *
 *  @param data     下载区域
 *  @param complete 下载回调
 */
- (void)downloadStartWithData:(NSData *)data complete:(void (^)(BOOL isFinish, NSString *filePath, long long downloadBytes, long long totalBytes))complete;

/**
 *  停止,或暂停下载
 */
- (void)downloadStop;

@end
// .m文件
#import "SYDownloadTask.h"

@interface SYDownloadTask () <NSURLSessionDownloadDelegate>

@property (nonatomic, strong) NSData *downloadData;
@property (nonatomic, copy) void (^DownloadComplete)(BOOL isFinish, NSString *filePath, long long downloadBytes, long long totalBytes);
@property (nonatomic, assign) BOOL isFinish;
@property (nonatomic, assign) long long downloadBytes;
@property (nonatomic, assign) long long totalBytes;

@property (nonatomic, strong) NSURLSessionDownloadTask *dataTask;
@property (nonatomic, strong) NSURLSession *dataSession;

@end

@implementation SYDownloadTask

#pragma mark - getter

- (NSURLSession *)dataSession
{
    if (!_dataSession)
    {
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
        _dataSession = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    }
                        
    return _dataSession;
}

- (NSData *)resumeData
{
    return self.downloadData;
}

#pragma mark - 方法

/**
 *  开始下载
 *
 *  @param url      下载地址
 *  @param complete 下载回调
 */
- (void)downloadStartWithURL:(NSString *)url complete:(void (^)(BOOL isFinish, NSString *filePath, long long downloadBytes, long long totalBytes))complete
{
    if (complete)
    {
        self.DownloadComplete = [complete copy];
    }

    NSURL *urlStr = [NSURL URLWithString:url];
    self.dataTask = [self.dataSession downloadTaskWithURL:urlStr];
    [self.dataTask resume];
}

/**
 *  继续下载
 *
 *  @param data     下载区域
 *  @param complete 下载回调
 */
- (void)downloadStartWithData:(NSData *)data complete:(void (^)(BOOL isFinish, NSString *filePath, long long downloadBytes, long long totalBytes))complete
{
    if (complete)
    {
        self.DownloadComplete = [complete copy];
    }
    
    self.dataTask = [self.dataSession downloadTaskWithResumeData:data];
    [self.dataTask resume];
}

/**
 *  停止,或暂停下载
 */
- (void)downloadStop
{
    __weak typeof(self) weakSelf = self;
    [self.dataTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
        weakSelf.downloadData = resumeData;
    }];
}

#pragma mark - NSURLSessionDownloadDelegate

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    self.isFinish = YES;
    
    // 将文件默认下载到我们的tmp文件夹中,我们还需要将该文件移动到我们的cache当中
    NSString *destPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
    NSString *fileName = [destPath stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager moveItemAtURL:location toURL:[NSURL fileURLWithPath:fileName] error:nil];
    
    // 下载完成
    if (self.DownloadComplete)
    {
        self.DownloadComplete(self.isFinish, fileName, self.downloadBytes, self.totalBytes);
    }
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    self.downloadBytes = totalBytesWritten;
    self.totalBytes = totalBytesExpectedToWrite;
    
    // 正在下载
    if (self.DownloadComplete)
    {
        self.DownloadComplete(self.isFinish, nil, self.downloadBytes, self.totalBytes);
    }
}


@end

2、使用断点续传下载类

// 导入头文件
#import "SYDownloadTask.h"
// 定义成属性
@property (nonatomic, strong) SYDownloadTask *downloadTask;
// 使用,即实例化,或开始,暂停下载,继续下载
- (void)buttonClick:(UIButton *)button
{
    if (button.selected)
    {
        if (self.downloadTask)
        {
            [self.downloadTask downloadStop];
        }
    }
    else
    {
        __weak typeof(self) weakSelf = self;
        if (self.downloadTask)
        {
            [self.downloadTask downloadStartWithData:self.downloadTask.resumeData complete:^(BOOL isFinish, NSString *filePath, long long downloadBytes, long long totalBytes) {
                
                NSLog(@"1 下载状态:%@", (isFinish ? @"下载完成" : @"正在下载"));
                NSLog(@"1 下载文件路径:%@", filePath);
                NSLog(@"1 已下载:%f%%(downloadBytes = %f, totalBytes = %f)", (float)(downloadBytes)/(float)(totalBytes), (float)downloadBytes, (float)totalBytes);
                
                weakSelf.progressView.progress = (float)(downloadBytes)/(float)(totalBytes);
                if (isFinish)
                {
                    button.selected = NO;
                }
            }];
        }
        else
        {
            NSString *string = @"http://sohu.vodnew.lxdns.com/193/142/tas6Zt4gReWdeh2eiBm7yD.mp4";
//            NSString *string = @"http://www.68mtv.com/index/down/id/61109";
//            NSString *string = @"http://imgsrc.baidu.com/baike/pic/item/203fb80e7bec54e7c5cda6b3bd389b504fc26a7e.jpg";
            self.downloadTask = [[SYDownloadTask alloc] init];
            [self.downloadTask downloadStartWithURL:string complete:^(BOOL isFinish, NSString *filePath, long long downloadBytes, long long totalBytes) {
                NSLog(@"2 下载状态:%@", (isFinish ? @"下载完成" : @"正在下载"));
                NSLog(@"2 下载文件路径:%@", filePath);
                NSLog(@"2 已下载:%f%%(downloadBytes = %f, totalBytes = %f)", (float)(downloadBytes)/(float)(totalBytes), (float)downloadBytes, (float)totalBytes);
                
                weakSelf.progressView.progress = (float)(downloadBytes)/(float)(totalBytes);
                if (isFinish)
                {
                    button.selected = NO;
                }
            }];
        }
    }
    
    button.selected = !button.selected;
}




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

番薯大佬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值