文件下载

1.小文件下载

1.1下载方式

  • 【NSData dataWithContentsOfURL:】
  • [NSURLConntection sendAsynch...]

劣势:无法下载大文件。原因是无法显示进度,用户体验很差;再有一口气下载完给内存,内存会爆的。

2.大文件下载

2.1 NSURLConnection基本下载

NSURL * **url =
NSURLRequest *request =
//下载(创建万conn对象后,会自动发起一个异步请求)
【NSURLConnection connectionWithRequest:requeset delegate:self】
这里面的代理就是监听下载进度的

有四个代理方法

//比如请求失败(请求超时,网络异常)
- (void)connection:(NSURLConnection *)connection didFailWithError:()error{}

//接收到服务器的响应就会调用
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
if(self.currentLength) return;
//取出文件的总长度
//NSHTTPURLResponse *resp = (NSHTTPURLRespone *)response;
//long long fileLength = [resp.allHeaderFields[@"Content--Length"]longlongValuse];
self.totalLength = response.expectedContentLength

//文件路径
NSString *cache = NSSearchPathForDir.....
NSString *filePath = [cache stringByAppendingPath...];
//创建一个空的文件到沙盒中
NSFileManager *mgr = [NSFileManager defaultManager];
[mgr createFileAtPath:filePath contents:nil attributes:nil];
//创建一个用来写数据的文件句柄,用来关联文件
self.writeHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
}

//当接收到服务器返回的实体数据时调用
- (void)connection:(NSURLConnection *)connection didReceiveDate:(NSData *)data{
static int total = 0;
self.currentLength  +=data.length
[self.fileData appendData:data];

self.progressView.progress = (double)self.currentLength  /self.totalLength

//移动到文件的最后面
[self.writeHandle seekToEndOfFile];
//写入数组
[self.wtiteHandle writeData:data];
}


//服务器的数据已经完全返回
- (void)connectionDidFinshLoading:(NSURLConnection *)connection {
[self.writeHandle closeFile];
self.WtriteHandle = nil;
}

要知道两个:总大小,现在下到那个地方了。总大小在响应头里面,有响应的大小和类型。

//写到沙盒中去,文件太大的话不要写到Document中,要是太大会被据。想要保存又不备份的话存到Library中的Caches中去;NSURLConnection的异步一个为block一个为代理

那么要是网络出问题,怎么从断点出接着下载,用按钮模拟。按钮的话状态取反就可以了。

- download:(UIButton *)sender{
sender.selected = !sender.isSelected;
if(sender.selected){//继续(开始)下载
NSURL *url =
NSMutableURLRequest *request = [NSMutableURLRequest requestWIthURl:url];
//设置请求头
NSString *range = [NSString stringWithFormat:@"bytes=%lld-",self.currentLength];
[request setValue:range forHttpHeaderFidle:@"Range"];
//下载(创建万conn对象后,会自动发起一个异步请求)
self.conn = 【NSURLConnection connectionWithRequest:requeset  delegate:self】
}else{//暂停
[self.coon cancel];
}
}

2.2多线程断点下载

思路 :这个就要用到一开始就要在沙盒中创建一个一样大小的文件,里面是01的二进制.之后根据range的来分为几个线程。每个线程下载的部分存入到沙盒中的固定位置。

2.3 NSURLSession

2.3.1基本掌握

相对来说,从post、get请求上没有比NSURLConnection精简多少,比较出众的地方在文件下载.当我们下载文件时,它的内部是直接存储到沙盒中的temp文件中,所以我们要对文件进行处理,要不会别删掉。把文件剪切到Library中的Caches文件中。是iOS7退出来替代NSURLConnection。
**
任务:任何请求都是一个任务
NSURLSessionDataTask:普通的get、post请求
NSURLSessionDownloadTask:文件的下载
优点:边下载变缓存到沙盒的temp文件中,而且方便断点续传。
NSURLSessionUploadTask:文件的上传
**

- (void)touchesBegan:{


}

//下载进度2
 - (void)download2{
//
NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration  defaultSessionConfiguration]; 
//得到session对象
NSURLSession *session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSQperationQueue mainQueue]];
//创建一个下载task
NSURL *url = [NSURL urlWithString:@"http:..."];
NSURLSessionDownloadTask *task  = [session downloadWithTaskWithURL:url ];

//要是handle这个block的话,优先执行block,不会执行协议
//开始任务
[task resume];
}

//代理的方法


//下载完后的路径
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
//将临时文件剪切或者复制到Caches文件夹
NSString *cachs = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject];
//:response.suggestedFilename:建议使用的文件名,一般跟服务器端的文件名一样
NSString *file = [caches stringByAppendingPathComponent:downloadTask.response.suggestedFilename];

//将临时文件剪切或者复制Caches文件夹
NSFileMagnger *age = [NSFileManger defaultManger]; 
[mgr moveItemAtPath:location.path toPath:file error:nil];
}


/ **第一个参数:bytesWritten 这次调用写了多少
totalBytesWritten 累计写入多少长度到沙盒中
totalBytesExpectedToWrite 文件的总长度
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)byteWtitten totalBytesWritten  totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {

double progress = (double )totalBytesWritten /totalBytesExpectedToWrite ;

}




//下载任务:不能看到下载进度
- (void)download{
//得到一个session对象
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL urlWithString:@"http:..."];

NSURLSessionDownloadTask *task  = [session downloadWithTaskWithURL:url completionHandle:^(NSURL*location,NSURLRespone *respone ,NSError *error)]{
//location:临时文件的路径(下载好的文件)

//将临时文件剪切或者复制到Caches文件夹
NSString *cachs = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject];
//:response.suggestedFilename:建议使用的文件名,一般跟服务器端的文件名一样
NSString *file = [caches stringByAppendingPathComponent:response.suggestedFilename];

//将临时文件剪切或者复制Caches文件夹
NSFileMagnger *age = [NSFileManger defaultManger]; 
[mgr moveItemAtPath:location.path toPath:file error:nil];

}];
//开始任务
[task resume];

}

- (void)dataTask{
//得到一个session对象
NSURLSession *session = [NSURLSession sharedSession];
//创建一个task任务
NSURL *url = [NSURL urlWithString:@"http:..."];

//创建一个请求 ,这是一个post请求,get的话差不多
NSMurableURLRequest *request =[NSMurableURLRequest  requestWithURL:url];
reuqest.HTTPMethod = @"POST";
//设置请求体,先不加密了。转为请求提Data
request.HTTPBody = [@"username=123&pwd=123" dataUseingEncoding:NSUTF8StringEncoding];

//在这里存入到沙盒中的temp文件夹中
NSURLSessionDataTask *task  = [session dataTaskWithRequest:request completionHandle:^(NSData *data,NSURLRespone *respone ,NSError *error)]{
//假设服务器返回的是字典
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData :data options :NSJSONReadingMutableLeaves error:nil];

NSFileMagnger *age = [NSFileManger defaultManger];
NSSearchPathDicteciory * = []
}

}

2.3.2断点下载

- download:(UIButton *)sender{
//按钮状态取反
sender.selected = !sender.isSelected;
if(self.task == nil){//继续(开始)下载
if(self.resumeData){
[self.resumeData];//恢复
}else {
[self start];//开始
}
}else{//暂停
[selfcancel];
}
}


- (void)start{

NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration  defaultSessionConfiguration]; 
//得到session对象
NSURLSession *session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSQperationQueue mainQueue]];
//创建一个下载task
NSURL *url = [NSURL urlWithString:@"http:..."];
self*task  = [session downloadWithTaskWithURL:url ];

//开始任务
[self.task resume];

}

- (void)resume{

NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration  defaultSessionConfiguration]; 
//得到session对象, 这里面的队列是存放代理方法和block,这样的话我们获取数据的就是为了刷新UI,还有方法调用太频繁,这样我们就放入到主线程里面。
NSURLSession *session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSQperationQueue mainQueue]];

//传入上次暂停下载返回的数据,就可以恢复下载
self.task = [self.session downloadTaskWithResumeData:self.resumeData];

//开始任务
[self.task resume];

//清空
self.resumeData = nil;

}

- (void)pause{
//self引用了task,而task又用了block,里面又点上了属性,所以要weak下
__weak typeof(self )vc = self;
[self.task cancelByProducingResumeData:^(NSData *resumeData){
//resumeData :包含了继续下载的开始位置和下载的URL
vc.resumeData = resumeData;
vc.task = nil;

}];
}


//协议方法

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{

//将临时文件剪切或者复制到Caches文件夹
NSString *cachs = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject];
//:response.suggestedFilename:建议使用的文件名,一般跟服务器端的文件名一样
NSString *file = [caches stringByAppendingPathComponent:downloadTask.response.suggestedFilename];

//将临时文件剪切或者复制Caches文件夹
NSFileMagnger *age = [NSFileManger defaultManger]; 
[mgr moveItemAtPath:location.path toPath:file error:nil];
}


3.文件上传

文件上传要首先服务器要有这个功能,
用HTTP的post就可以达到文件上传,像是图片,音乐,视频,文件等。

4.AFN

4.1基本使用(下载)

AFN是基于NSURLConnection和NSURLSession,之后才是CFNetwork,而ASI基于CFNetwork所以效率上时ASI快些。

AFHTTPRequestOperationManager是AFN中最重要的对象之一,封装了HTTP请求的常见处理GET\POST请求,解析服务器的响应数据。

二大管理对象

  • AFHTTPRequestOperationManager:对NSURLCOnnection的封装

  • AFHTPSessionManager:对NSURLSession的封装

AFHTTPRequestOperationManager的具体使用
1.创建管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
2.封装请求参数
//请求参数,用可变字典就是代码规范
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";

3.发送请求
这个是在异步线程中,不用我们再调回主线程中。
[[NSOperationQueue mainQueue] addOperation:任务];

  • [ mgr GET:url parameters:params
    success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success{

}
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{

}

并且AFN对服务器返回的数据进行解析,默认为JSON来解析。我们也可以自己设置解析方式,像是XML和NSData。
//选择序列化器
mgr.responseSerializer = [AFXMLParserResponseSerializer serializer];
*** 服务器返回的数据一定要跟respoSerializer对的上**


- (void)teachesBegan...{

}

- (void)getPost{
//创建
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
//默认为JSON
mgr.responseSerializer = [AFJSONParserResponseSerializer serializer];
//请求参数,用可变字典就是代码规范
NSMutableDictionary *params = [NSMutableDictionary  dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";

NSString *url @"http:///..";
//GET请求 并且params 里面是中文的话AFN也会转码,responseObject也是字典不是NSData,也不用我们去转换格式,那么想把二进制转为字符串,添加一个分类Foundation+log分类
- [ mgr POST:url   parameters:params
                        success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success{

}
                        failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{

}
}

//这个就无法转为字典了
- (void)XML{
//创建
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
//选择序列化器
mgr.responseSerializer = [AFXMLParserResponseSerializer serializer];
//请求参数,用可变字典就是代码规范
NSMutableDictionary *params = [NSMutableDictionary  dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";
pparams[@"type"] = @"XML";
NSString *url @"http:///..";
//GET请求 并且params 里面是中文的话AFN也会转码,responseObject也是字典不是NSData,也不用我们去转换格式,那么想把二进制转为字符串,添加一个分类Foundation+log分类
- [ mgr GET:url   parameters:params
                        success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success{

}
                        failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{

}

}
}
//想下载的数据比如图片和文件不像转为JSON或者是XML,就是NSData
- (void)getData{
//创建
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
//默认为JSON
mgr.responseSerializer = [AFHTTPResponseSerializer serializer];
//请求参数,用可变字典就是代码规范
NSMutableDictionary *params = [NSMutableDictionary  dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";

NSString *url @"http:///..";
//GET请求 并且params 里面是中文的话AFN也会转码,responseObject也是字典不是NSData,也不用我们去转换格式,那么想把二进制转为字符串,添加一个分类Foundation+log分类
 [ mgr GET:url   parameters:params
                        success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success{
//要是XML数据,想要解析那么
NSXMLParser *parser = [NSXMLParser alloc] initWithData :responseObject];
}
                        failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{

}

}
//AFHTTPRequestOperationManager是对NSURLConnection的封装
- (void)getJSON{
//创建
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
//默认为JSON
mgr.responseSerializer = [AFJSONParserResponseSerializer serializer];
//请求参数,用可变字典就是代码规范
NSMutableDictionary *params = [NSMutableDictionary  dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";

NSString *url @"http:///..";
//GET请求 并且params 里面是中文的话AFN也会转码,responseObject也是字典不是NSData,也不用我们去转换格式,那么想把二进制转为字符串,添加一个分类Foundation+log分类
 [ mgr GET:url   parameters:params
                        success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success{

}
                        failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure{

}]

}


4.2文件上传

文件上传
AFN不支持文件上传进度查看,ASI支持。而文件较大时,断点续传的技术一般的HTTP服务器都不支持,常用的技术用的是Socket(TCP\IP)


- (void)teachesBegan:(NSSet *)ouches withEvent:(UIEvent *)event{
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle :@"选择图片" delegate:self cncelButtonTitl:@"cancel" destructiveButtonTitle:nil otherButtonTitles:@"拍照",@"相册"];

[sheet showInView:self.view.window];
** 写的时候出了一个错,就是当莫打出一个控制器的时候,sheet还没有销毁,但是却无法show in 控制器上就出错了,所以添加到window上,这样view不在窗口上的话也没有事情 **
}
//UIActionSheet 代理方法
- (void)actionSheet :(UIActionSheet *)actionSheet cickedButtonAtIndex:(NSInteger)buttonIndex{
//switch语法在里面定义变量的话要有
//上传手机的图片给服务器,上传来源:拍照 相册
UIImagePickerController  *ipc = [[UIImagePickerController alloc ]init];
//设置代理
ipc.delegate = self;
switch (butonIndex){
case 0 :{
if(![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) return;
//设置图片的来源
ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
break;
}
case 1:{
if(![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhoto]) return;
//设置图片的来源
ipc.sourceType = UIImagePickerControllerSourceTypePhoto;
break;
}
}

[self presentiewController:ipc animated:YES completion:nil]; 
}


//UIImagePickerController 代理方法
//info 里面包含了图片信息
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
//销毁控制器
[picker dismissViewCOntrollerAnimated:YES completion:nil];
//获得图片
UIImage *image = info[UIImagePickerControllerOriginalImage];

}


- (void)upload{
//创建一个管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
//封装参数,这里放非文件参数
NSMutableDictionary *params = [NSMutableDictionary  dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";

NSString *url @"http:///..";

 [ mgr POST:url   parameters:params  constructingBodyWithBlock:^(id<AFMultipatrFormData> formData){
//在发送请求之前会自动调用这个block,在这里添加文件参数到formData中
/**
FileURL:需要上传的文件的URL路径
name:服务器那边接收文件用的参数名
fileName :(告诉服务器)所长传文件的文件名
mimeType:所上传文件的文件类型

[formData appendPartWithFileURL :url name :@"" fileName :  mimeType:  error: ];
*/

//FileData:所上传的文件的具体数据
UIImage *image = [UIImage imageNamed:@"min_01"];
NSData *fileData = UIImagePNGRepresentation(image);

[formData appendPartWithFileData :fileData   name :@"file" fileName :@"haha.png"  mimeType:@"image/png"  error: nil];

} success:^(AFHTTPRequestOperation *operation, id responseObject)success{

}
                        failure:^(AFHTTPRequestOperation *operation, NSError *error)failure{

}];

}

4.3监听网络状态

苹果原生的非常麻烦,AFN自己封装了一个

- (void)viewDidLoad{
AFNetworkReachabilitManager *mgr = [AFNetworkReachabilitManager  sharedManager];

[mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilitManager  status){
//当前网络状态发生改变的时候调用这个block
switc(status){
case AFNetworkReachabilityStatusReachableViaFi; break;
case AFNetworkReachabilityStatusReachableWWAN; break;
case AFNetworkReachabilityStatusNotReachable; break;

}


}]
//开始监控
[mgr startMonitoring];

}

- (void)dealloc{
[[AFNetworkReachabilitManager  sharedManager] stopMonitoring];
}


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容