对下载文件进行处理,每下载一点数据,就将数据写到磁盘中(通常是沙盒中),避免在内存累积数据(NSURLConnection下载)
当下载任务终止时,记录任务终止时的位置信息,以便下次开始继续下载
使用 NSFileHandle 类实现写数据的下载步骤( 完整核心代码
)
设置相关成员属性
/**所要下载文件的总长度*/ @property (nonatomic, assign) NSInteger contentLength; /**已下载文件的总长度*/ @property (nonatomic, assign) NSInteger currentLength /**文件句柄,用来实现文件存储*/ @property (nonatomic, strong) NSFileHandle *handle;
创建、发送请求
// 1. 创建请求路径 NSURL *url = [NSURL URLWithString:@"此处为URL字符串"]; // 2. 将URL封装成请求 NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 3. 通过NSURLConnection,并设置代理 [NSURLConnection connectionWithRequest:request delegate:self];
遵守代理协议NSURLConnectionDataDelegate,实现代理方法
/** * 接收到服务器响应时调用的方法 */ - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response { //获取所要下载文件的总长度 self.contentLength = [response.allHeaderFields[@"Content-Length"] integerValue]; //拼接一个沙盒中的文件路径 NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"minion_15.mp4"]; //创建指定路径的文件 [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil]; //创建文件句柄 self.handle = [NSFileHandle fileHandleForWritingAtPath:filePath]; } /** * 接收到服务器的数据时调用的方法 */ - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { //定位到文件尾部,将服务器每次返回的文件数据都拼接到文件尾部 [self.handle seekToEndOfFile]; //通过文件句柄,将文件写入到沙盒中 [self.handle writeData:data]; //拼接已下载文件总长度 self.currentLength += data.length; //计算下载进度 CGFloat progress = 1.0 * self.currentLength / self.contentLength; } /** * 文件下载完毕时调用的方法 */ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { //关闭文件句柄,并清除 [self.handle closeFile]; self.handle = nil; //清空已下载文件长度 self.currentLength = 0; }
使用 NSOutputStream 类实现写数据的下载步骤( 部分代码,其他部分代码同上
)
设置NSOutputStream成员属性
@property (nonatomic, strong) NSOutputStream *stream;
初始化NSOutputStream对象,打开输出流
/**接收到服务器响应的时候调用*/ - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { //获取下载数据保存的路径 NSString *cache = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; NSString *filePath = [cache stringByAppendingPathComponent:response.suggestedFilename]; //利用NSOutputStream往filePath文件中写数据,若append参数为yes,则会写到文件尾部 self.stream = [[NSOutputStream alloc] initToFileAtPath:filePath append:YES]; //打开数据流 [self.stream open]; }
写文件数据
/**接收到数据的时候调用*/ - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [self.stream write:[data bytes] maxLength:data.length]; }
关闭输出流
/**数据下载完毕的时候调用*/ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { [self.stream close]; }
详细的下载步骤
设置下载任务task的为成员变量
@property (nonatomic, strong) NSURLSessionDownloadTask *task;
获取NSURLSession对象
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
初始化下载任务任务
self.task = [session downloadTaskWithURL:(此处为下载文件路径URL)];
实现代理方法
/**每当写入数据到临时文件的时候,就会调用一次该方法,通常在该方法中获取下载进度*/ - (void)URLSession:(NSURLSession *)session downloadTask: (NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { // 计算下载进度 CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite; } /**任务终止时调用的方法,通常用于断点下载*/ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes { //fileOffset:下载任务中止时的偏移量 } /**遇到错误的时候调用,error参数只能传递客户端的错误*/ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { } /**下载完成的时候调用,需要将文件剪切到可以长期保存的文件夹中*/ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { //生成文件长期保存的路径 NSString *file = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename]; //获取文件句柄 NSFileManager *fileManager = [NSFileManager defaultManager]; //通过文件句柄,将文件剪切到文件长期保存的路径 [fileManager moveItemAtURL:location toURL:[NSURL fileURLWithPath:file] error:nil]; }
操作任务状态
/**开始/继续下载任务*/ [self.task resume]; /**暂停下载任务*/ [self.task suspend];