iOS网络编程---根据URL下载网络文件的方法

下面是源码,注释掉的部分代码是一次性下载的功能(不推荐),正常运行的代码实现了:

- 功能:根据提供的URL下载网络文件

PS:其中有6个关键字,是实现该功能使用到的知识点,我在代码的后面做了必要的归纳和整理。

#define kReceivedTotal @"receivedTotal"
#define kTotal @"total"
#import "ViewController.h"

@interface ViewController () <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
{
    //全局连接对象,用来取消下载
    NSURLConnection *_connection;

    double _totalLength;    //获取数据总长度
    NSMutableData *_totalData;    //接收到的数据
    double _receiveLength;    //接收到的数据长度

    //判断是否正在下载
    BOOL isDownloading;

    //下载文件路径
    NSString *_filePath;
}
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];

//①:NSUserDefaults类
-------------------    
    //读取本地化的plist文件,获取已下载数据量和文件总大小
    NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
    _receiveLength = [[userDefault objectForKey:kReceivedTotal] doubleValue];
    _totalLength = [[userDefault objectForKey:kTotal] doubleValue];

    //作用:程序退出后会记录退出前下载的情况,下一次进入后会根据上一次退出时的情况改变progress和label的样式
    if (_totalLength > 0) {
        double progress = _receiveLength / _totalLength;
        _progressLabel.text = [NSString stringWithFormat:@"%.2f%%", progress*100];
        _progressLine.progress = progress;
    }

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - 按钮:点击下载方法
- (IBAction)startDownload:(UIButton *)sender {
    //如果点击下载按钮立即跳出下载完成,很可能试url有问题。此处找的是QQ音乐上的url,第二天便会更新
    //isDownloading:用于判断下载状态。进入下载时为YES,下载完成时为NO
    if (!isDownloading) {
        NSURL *url = [NSURL URLWithString:@"http://218.205.82.11/mobileoc.music.tc.qq.com/F000003BiKB44LknC0.flac?continfo=122542B50C9B1A0317535549A8AD143E8038EA7648884166&vkey=8078E72D66A07AD5C4B3696E52E8702B0612145B7EFF5BBB77FEAB63A1D6673DE51521C2D4397D8D659204309621EBB8EABA0FFD614A4171&guid=27238e629f2f6ffc850c749439bf81a1824fc41d&fromtag=55&uin=290363831"];

//②:NSURLRequest
----------------
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        //通过http下载请求头来设置继续下载的位置
        NSString *value = [NSString stringWithFormat:@"bytes=%i-", (int)_receiveLength];
        [request setValue:value forHTTPHeaderField:@"Range"];
        //NSLog(@"继续下载:%@", request.allHTTPHeaderFields);

//③:NSURLConnection
-------------------
        //发送异步网络请求
        _connection = [NSURLConnection connectionWithRequest:request delegate:self];

        //此时正在下载
        isDownloading = YES;


        //1.下面是不设置断点续传时的写法:在路径下直接创建单例文件用于保存下载到的数据

//④:NSFileManager
-----------------

//        //创建空文件来保存下载数据
//        NSString *fileName = @"听爸爸的话.mp3";
//        _filePath = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/%@", fileName];
//        //为路径创建单例
//        [[NSFileManager defaultManager] createFileAtPath:_filePath contents:nil attributes:nil];

        //2.断点续传的写法
        //创建临时目录路径
        _filePath = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/tmp/%@", @"听爸爸的话.mp3"];
        //NSLog(@"%@", _filePath);

        //判断临时文件是否存在,如果不存在则创建
        if (![[NSFileManager defaultManager] fileExistsAtPath:_filePath]) {
            //先创建临时文件夹
            NSString *dirPath = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/tmp"];
            [[NSFileManager defaultManager] createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:nil];
            //创建空的临时文件
            [[NSFileManager defaultManager] createFileAtPath:_filePath contents:nil attributes:nil];
        }
    }
}

#pragma mark - 按钮:点击暂停下载方法
- (IBAction)cancelDownload:(UIButton *)sender {
    //取消下载
    [_connection cancel];

    //把数据包存入文件
    [self appendFileData:_totalData];

    //释放内存
    _totalData.data = nil;
    isDownloading = NO;

    //暂停时,保存已下载数据量和文件总数量到本地,保证程序退出后下次进入仍然可以实现断点续传
    [self saveUserDefaulst];
}


#pragma mark - 文件写入方法
-(void) appendFileData:(NSData *) data {
    if (data.length == 0 || _filePath.length == 0) {
        //文件有误
        return;
    }

//⑤:NSFileHandle
----------------
    NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:_filePath];
    [fileHandle seekToEndOfFile];
    [fileHandle writeData:data];
    [fileHandle closeFile];
}

#pragma mark - NSURLConnectionDelegate
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
    //获取响应头
    NSDictionary *fields = httpResponse.allHeaderFields;

    //获取下载文件的总长度
    if (_totalLength == 0) {
        NSNumber *length = fields[@"Content-Length"];
        _totalLength = [length doubleValue];
    }
    //用于存放下载得到的数据,这是存放在内存中的
    _totalData = [[NSMutableData alloc] init];
}

-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {    
//    double progress = _totalData.length / _totalLength;

    //根据当前下载的数据包大小来刷新进度条和Label的现实
    [_totalData appendData:data];
    _receiveLength += data.length;
    double progress = _receiveLength / _totalLength;

    //刷新UI
    self.progressLabel.text = [NSString stringWithFormat:@"%.2f%%", progress*100];
    self.progressLine.progress = progress;

    if (_totalData.length > 500*1024) {
        [self appendFileData: _totalData];

        //释放内存
        _totalData.data = nil;
    }
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
    //方法1:该写法用于一次性完整下载(不推荐)
//    //下载完成后保存数据到本地
//    NSURL *url = connection.currentRequest.URL;
//    NSString *urlString = url.absoluteString;
//    NSString *fileName = urlString.lastPathComponent;
//    
//    //根据?分割符存放数据到数组
//    NSArray *array = [fileName componentsSeparatedByString:@"?"];
//    //获取文件名
//    fileName = array[0];
//    
//    //获取沙盒路径
//    NSString *filePath = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/%@", fileName];
//    NSLog(@"%@", filePath);
//    
//    //把数据写入文件
//    [_totalData writeToFile:filePath atomically:YES];

    //方法2:该方法满足了断点下载,虽然增大了开销但是确保了下载的安全性
    //文件末尾不足500KB大小的数据也要写入文件,所以文件下载“完成”后还要调用一个appendFileData方法
    [self appendFileData:_totalData];
    //清楚缓存
    _totalData.data = nil;

    self.progressLabel.text = @"下载完成";
    isDownloading = NO;

    //将下载完成的文件从临时目录剪切到目的目录
    NSFileManager *manager = [NSFileManager defaultManager];

    //确定目录文件路径
    NSString *targetFilePath = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/%@", @"听爸爸的话.mp3"];
    //判断目标文件是否存在,如果存在把旧文件删除,准备剪切操作
    if ([manager fileExistsAtPath:targetFilePath]) {
        [manager removeItemAtPath:targetFilePath error:nil];
    }
    //剪切方法的限制:不能把已经存在文件覆盖,如果此文件存在,在剪切之前需要先删除
    [manager moveItemAtPath:_filePath toPath:targetFilePath error:nil];

    //保存数据
    [self saveUserDefaulst];

    //下载完成把已下载数据量和文件总大小清零
    _receiveLength = 0;
    _totalLength = 0;
}

#pragma mark - NSUserDefaults 保存下载的数据量和文件数据量到本地
-(void) saveUserDefaulst {
    //下载完成时,保存已下载数据量和文件宗数据量到本地
    NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
    [userDefault setObject:@(_receiveLength) forKey:kReceivedTotal];
    [userDefault setObject:@(_totalLength) forKey:kTotal];
    //数据同步写入到plist文件
    [userDefault synchronize];
}
@end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值