AZ_大文件处理,文件的压缩和解压缩
5.0 大文件的下载
(1)实现思路
边接收数据边写文件以解决内存越来越大的问题
(2)核心代码
//当接收到服务器响应的时候调用,该方法只会调用一次
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//0.获得当前要下载文件的总大小(通过响应头得到)
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
self.totalLength = res.expectedContentLength;
NSLog(@"%zd",self.totalLength);
//创建一个新的文件,用来当接收到服务器返回数据的时候往该文件中写入数据
//1.获取文件管理者
NSFileManager *manager = [NSFileManager defaultManager];
//2.拼接文件的全路径
//caches文件夹路径
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *fullPath = [caches stringByAppendingPathComponent:res.suggestedFilename];
self.fullPath = fullPath;
//3.创建一个空的文件
[manager createFileAtPath:fullPath contents:nil attributes:nil];
}
//当接收到服务器返回的数据时会调用
//该方法可能会被调用多次
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//1.创建一个用来向文件中写数据的文件句柄
//注意当下载完成之后,该文件句柄需要关闭,调用closeFile方法
NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];
//2.设置写数据的位置(追加)
[handle seekToEndOfFile];
//3.写数据
[handle writeData:data];
//4.计算当前文件的下载进度
self.currentLength += data.length;
NSLog(@"%f",1.0* self.currentLength/self.totalLength);
self.progressView.progress = 1.0* self.currentLength/self.totalLength;
}
6.0 大文件断点下载
(1)实现思路
在下载文件的时候不再是整块的从头开始下载,而是看当前文件已经下载到哪个地方,然后从该地方接着往后面下载。可以通过在请求对象中设置请求头实现。
(2)解决方案(设置请求头)
//2.创建请求对象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//2.1 设置下载文件的某一部分
// 只要设置HTTP请求头的Range属性, 就可以实现从指定位置开始下载
/*
表示头500个字节:Range: bytes=0-499
表示第二个500字节:Range: bytes=500-999
表示最后500个字节:Range: bytes=-500
表示500字节以后的范围:Range: bytes=500-
*/
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentLength];
[request setValue:range forHTTPHeaderField:@"Range"];
(3)注意点(下载进度并判断是否需要重新创建文件)
//获得当前要下载文件的总大小(通过响应头得到)
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
//注意点:res.expectedContentLength获得是本次请求要下载的文件的大小(并非是完整的文件的大小)
//因此:文件的总大小 == 本次要下载的文件大小+已经下载的文件的大小
self.totalLength = res.expectedContentLength + self.currentLength;
NSLog(@"----------------------------%zd",self.totalLength);
//0 判断当前是否已经下载过,如果当前文件已经存在,那么直接返回
if (self.currentLength >0) {
return;
}
7.0 输出流
(1)使用输出流也可以实现和NSFileHandle相同的功能
(2)如何使用
//1.创建一个数据输出流
/*
第一个参数:二进制的流数据要写入到哪里
第二个参数:采用什么样的方式写入流数据,如果YES则表示追加,如果是NO则表示覆盖
*/
NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:fullPath append:YES];
//只要调用了该方法就会往文件中写数据
//如果文件不存在,那么会自动的创建一个
[stream open];
self.stream = stream;
//2.当接收到数据的时候写数据
//使用输出流写数据
/*
第一个参数:要写入的二进制数据
第二个参数:要写入的数据的大小
*/
[self.stream write:data.bytes maxLength:data.length];
//3.当文件下载完毕的时候关闭输出流
//关闭输出流
[self.stream close];
self.stream = nil;
8.0 使用多线程下载文件思路
01 开启多条线程,每条线程都只下载文件的一部分(通过设置请求头中的Range来实现)
02 创建一个和需要下载文件大小一致的文件,判断当前是那个线程,根据当前的线程来判断下载的数据应该写入到文件中的哪个位置。(假设开5条线程来下载10M的文件,那么线程1下载0-2M,线程2下载2-4M一次类推,当接收到服务器返回的数据之后应该先判断当前线程是哪个线程,假如当前线程是线程2,那么在写数据的时候就从文件的2M位置开始写入)
03 代码相关:使用NSFileHandle这个类的seekToFileOfSet方法,来向文件中特定的位置写入数据。
04 技术相关
a.每个线程通过设置请求头下载文件中的某一个部分
b.通过NSFileHandle向文件中的指定位置写数据
9.0 文件的压缩和解压缩
(1)说明
使用ZipArchive来压缩和解压缩文件需要添加依赖库(libz),使用需要包含SSZipArchive文件,如果使用cocoaPoads来安装框架,那么会自动的配置框架的使用环境
(2)相关代码
//压缩文件的第一种方式
/*
第一个参数:压缩文件要保存的位置
第二个参数:要压缩哪几个文件
*/
[SSZipArchive createZipFileAtPath:fullpath withFilesAtPaths:arrayM];
//压缩文件的第二种方式
/*
第一个参数:文件压缩到哪个地方
第二个参数:要压缩文件的全路径
*/
[SSZipArchive createZipFileAtPath:fullpath withContentsOfDirectory:zipFile];
//如何对压缩文件进行解压
/*
第一个参数:要解压的文件
第二个参数:要解压到什么地方
*/
[SSZipArchive unzipFileAtPath:unZipFile toDestination:fullpath];