文件下載

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閱讀 228,030評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內容