一、传统的下载文件的方式
- (void)downloaderWithUrl:(NSURL *)url { NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { if (!connectionError) { NSHTTPURLResponse *urlResponse = (NSHTTPURLResponse *)response; if (urlResponse.statusCode == 200 || urlResponse.statusCode == 304) { [data writeToFile:@"/Users/gxiangzi/Desktop/a.mp4" atomically:YES]; NSLog(@"OK"); } }else { NSLog(@"错误"); } }]; }
但是这种方式存在着弊端:
1> 用不无法跟踪下载的进度,无法直观的显示下载进度
2> 文件下载的时候,都会先下载到内存之中,导致内存 > 所需文件的大小长度,会造成程序崩溃等现象(可以查看内存的耗费)
二、代理的方式下载程序(NSURLConnectionDownloadDelegate)
#import "GXDownloader.h" @interface GXDownloader () <NSURLConnectionDownloadDelegate> @end @implementation GXDownloader - (void)downloaderWithUrl:(NSURL*)url { NSURLRequest* request = [NSURLRequest requestWithURL:url]; [[NSURLConnection alloc] initWithRequest:request delegate:self]; } #pragma mark - NSURLConnectionDownloadDelegate /** bytesWritten: 表示下载的数据字节数 totalBytesWritten:总的已经下载的字节数 expectedTotalBytes:期望的总的字节数 */ - (void)connection:(NSURLConnection*)connection didWriteData:(long long)bytesWritten totalBytesWritten:(long long)totalBytesWritten expectedTotalBytes:(long long)expectedTotalBytes { float progress = (float)totalBytesWritten / expectedTotalBytes; NSLog(@"%f", progress); } /** * @param connection * @param totalBytesWritten : 总的已经下载的字节数 * @param expectedTotalBytes : 期望总的字节数 */ - (void)connectionDidResumeDownloading:(NSURLConnection*)connection totalBytesWritten:(long long)totalBytesWritten expectedTotalBytes:(long long)expectedTotalBytes { } /** * @param connection * @param destinationURL:下载完的目标路径 */ - (void)connectionDidFinishDownloading:(NSURLConnection*)connection destinationURL:(NSURL*)destinationURL { NSLog(@"%@", destinationURL); }
优点:
1> 该种方式可以跟踪文件下载的进度;
2> 也可以解决内存消耗过大的问题
弊端: 这丫的 下载的文件没有 ,就是虽然你显示下载完成,但是你本地找不到该文件------没有任何卵用
三、第三种方式--代理(NSURLConnectionDataDelegate)
// // GXDownloader.m // 02-下载 // // Created by gxiangzi on 15/8/21. // Copyright (c) 2015年 hqu. All rights reserved. // #import "GXDownloader.h" @interface GXDownloader () <NSURLConnectionDataDelegate> // 文件的总长度 @property (nonatomic, assign) long long expectedContentLength; // 已经接受到文件的长度 @property (nonatomic, assign) long long receivedContentLength; // 已经接收到的文件的总长度 @property (nonatomic, strong) NSMutableData* receivedData; @end @implementation GXDownloader - (void)downloaderWithUrl:(NSURL*)url { NSURLRequest* request = [NSURLRequest requestWithURL:url]; [[NSURLConnection alloc] initWithRequest:request delegate:self]; } #pragma mark - NSURLConnectionDataDelegate /** * 已经接受到响应头 */ - (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response { self.expectedContentLength = response.expectedContentLength; } /** * 文件接受到一点的时候就是用 */ - (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { // 把二进制数据进行拼接 [self.receivedData appendData:data]; // 拼接长度 self.receivedContentLength += data.length; float progress = (float)self.receivedContentLength / self.expectedContentLength; NSLog(@"下载进度: %.2f",progress); } /** * 下载出错的时候调用 */ - (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error { } /** * 当下载完成的时候调用 */ - (void)connectionDidFinishLoading:(NSURLConnection*)connection { NSLog(@"下载完成"); // IOS 的文件路径,只能讲软件操作的数据放在沙盒内 NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; NSString *fileName = [path stringByAppendingPathComponent:@"love.mp4"]; NSLog(@"%@",fileName); [self.receivedData writeToFile:fileName atomically:YES]; } #pragma mark -懒加载 - (NSMutableData*)receivedData { if (!_receivedData) { _receivedData = [NSMutableData data]; } return _receivedData; } @end
优点:
1> 可以检测到进度的问题
2> 文件的写入的路径之中,文件可以存在
弊端:
占用的内存太大
为了解决上面的问题: 引入了NSHandle 和 NSOutputStream ------下一点 写入文件一点
四、NSHandle的使用
// // GXDownloader.m // 02-下载 // // Created by gxiangzi on 15/8/21. // Copyright (c) 2015年 hqu. All rights reserved. // #import "GXDownloader.h" @interface GXDownloader () <NSURLConnectionDataDelegate> // 文件的总长度 @property (nonatomic, assign) long long expectedContentLength; // 已经接受到文件的长度 @property (nonatomic, assign) long long receivedContentLength; @end @implementation GXDownloader - (void)downloaderWithUrl:(NSURL*)url { NSURLRequest* request = [NSURLRequest requestWithURL:url]; [[NSURLConnection alloc] initWithRequest:request delegate:self]; } #pragma mark - NSURLConnectionDataDelegate /** * 已经接受到响应头 */ - (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response { self.expectedContentLength = response.expectedContentLength; } /** * 文件接受到一点的时候就是用 */ - (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { // 拼接长度 self.receivedContentLength += data.length; float progress = (float)self.receivedContentLength / self.expectedContentLength; NSLog(@"%f",progress); NSString* path = @"/Users/gxiangzi/Desktop/a.mp4"; NSFileHandle* handle = [NSFileHandle fileHandleForWritingAtPath:path]; // 如果handle 不会帮我们创建文件 if (handle == nil) { [data writeToFile:path atomically:YES]; } else { //让offset指向文件的末尾,在末尾处追加数据 [handle seekToEndOfFile]; //写输入 [handle writeData:data]; //关闭 (等文件下载完成关闭更好) [handle closeFile]; } } /** * 当下载完成的时候调用 */ - (void)connectionDidFinishLoading:(NSURLConnection*)connection { NSLog(@"下载完成"); } @end
原理:下载一点数据 写一点数据
效果:能够达到占用很少内存
五、NSOutputStream的使用
// // GXDownloader.m // 02-下载 // // Created by gxiangzi on 15/8/21. // Copyright (c) 2015年 hqu. All rights reserved. // #import "GXDownloader.h" @interface GXDownloader () <NSURLConnectionDataDelegate> // 文件的总长度 @property (nonatomic, assign) long long expectedContentLength; // 已经接受到文件的长度 @property (nonatomic, assign) long long receivedContentLength; @property (nonatomic, strong) NSOutputStream* stream; @end @implementation GXDownloader - (void)downloaderWithUrl:(NSURL*)url { NSURLRequest* request = [NSURLRequest requestWithURL:url]; [[NSURLConnection alloc] initWithRequest:request delegate:self]; } #pragma mark - NSURLConnectionDataDelegate /** * 已经接受到响应头 */ - (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response { self.expectedContentLength = response.expectedContentLength; NSString* path = @"/Users/gxiangzi/Desktop/a.mp4"; // 注意 此处的url 为本地的路径 // 前面加 file:// 无效 // 只能使用 [NSURL fileURLWithPath:path] self.stream = [NSOutputStream outputStreamWithURL:[NSURL fileURLWithPath:path] append:YES]; [self.stream open]; } /** * 文件接受到一点的时候就是用 */ - (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { // 拼接长度 self.receivedContentLength += data.length; float progress = (float)self.receivedContentLength / self.expectedContentLength; NSLog(@"%f", progress); [self.stream write:data.bytes maxLength:data.length]; } /** * 当下载完成的时候调用 */ - (void)connectionDidFinishLoading:(NSURLConnection*)connection { NSLog(@"下载完成"); [self.stream close]; } - (NSOutputStream *)stream { if (_stream == nil) { _stream = [[NSOutputStream alloc] init]; } return _stream; } @end
时间: 2024-12-20 23:29:17