NSURLConnection文件上传
- 使用
POST Content-Type: multipart/form-data;
#define kBOUNDARY @"abc"
-(void)uploadFile:(NSString *)urlString fieldName:(NSString *)fieldName filePath:(NSString *)filePath{
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"post";
[request setValue:[NSString stringWithFormat:@"multipart/form-data;boundary=%@",kBOUNDARY] forHTTPHeaderField:@"Content-Type"];
request.HTTPBody = [self makeBodyWithfieldName:fieldName filePath:filePath];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *_Nullable response,NSData *_Nullable data,NSError *_Nullable connectionError){
NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",html);
}];
}
-(NSData *)makeBodyWithfieldName:(NSString *)fieldName filePath:(NSString *)filePath{
NSMutableData *mData = [NSMuatbelData data];
NSMutableString *mString = [NSMuatbleString string];
[mString appendFormat:@"--%@\r\n",kBOUNDARY];
[mString appendFormat:@"Content-Disposittion: form-data; name=\"%@\";filename=\"%@\"\r\n",fieldName,[filePath lastPathComponent]];
[mString appendString:@"Content-Type: image/hpeg\r\n"];
[mString appendString:@"\r\n"];
[nData appendData:[mString dataUsingEncoding:NSUTF8StringEncoding]];
NSData *data = [NSData dataWithContentsOfFile:filePath];
[mData appendData:data];
NSString *end = [NSString stringWithFormat:@"\r\n--%@--",kBOUNDARY];
[mData appendData:[end dataUsingEncoding:NSUTF8StringEncoding]];
return mData.copy;
}
请求体各项的含义
name 表单的name 属性值filename 传递给服务器的文件名Content-Type 告诉服务器传递的文件类型text/plain image/jpeg image/jpg image/png application/octet-stream 等- 二进制数据 要上传的NSData
------WebKitFormBoundaryuWw18YzUxr2ygEJi--
同时上传多个文件
- 拼接请求体时,用
NSArray 的循环block 进行拼接 - 建议使用
AFNetworking
HEAD请求
HEAD 请求 不获取响应体只获取响应头 一般在下载之前先获取文件的大小NSURLResponse 的属性 MIMEType 返回的文件的类型 Content-Type expectedContentLength 文件的预期大小(实际大小) suagestedFilename 建议保存的文件的名字- 代码示例:异步请求
输出的data 是空的
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"post";
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *_Nullable response,NSData *_Nullable data,NSError *_Nullable connectionError){
NSLog(@"%@",response);
}];
文件下载
- 可以用
GET 下载,但是直接保存到内存中再进磁盘,内存压力大,内存不够闪退,没有进度条
[data writeToFile:@"/Users/Apple/Desktop/123.hm" atomically:YES];
NSURLConnectionDownloadDelegate 可以一点一点下载,有进度条,断点续传 但是只能用于报刊杂志类型的APP 文件保存,故放弃
遵守协议<NSURLConnectionDownloadDelegate>
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSURLConnection *conn = [NSURLConnection alloc]initWithRequest:request delegate:self];
代理方法:
-(void)connection:(NSURLConnection *)connection didWriteData:(long long)bytesWritten totalBytesWritten:(long long)totalBytesWritten expectedTotalBytes:(long long)expectedTotalBytes{
float process = totalBytesWritten *1.0 /expectedTotalBytes;
NSLog(@"%@",process);
}
-(void)connectionDidResumeDownloading:(NSURLConnection *)connection totalBytesWritten:(long long)totalBytesWritten expectedTotalBytes:(long long)expectedTotalBytes{
}
-(void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL{
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(@"下载出错%@",error)
}
NSURLConnectionDataDelegate NSURLConnectionDownloadDelegate 继承自NSURLConnectionDataDelegate
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
self.currentFileSize = response.expectedContentlength;
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
self.currentFileSize += data.length;
[self.mutableData appendData:data];
float process = self.currentFileSize *1.0 /expectedContentLength;
NSLog(@"%@",process);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(@"下载完成!");
[self.mutableData writeToFile:@"/Users/Apple/Desktop/111.hm" atomically:YES];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(@"下载出错%@",error)
}
解决内存爆涨
- 原因:把每次下载的二进制数据,累加到内存中
- 解决:每次接收到二进制文件数据后,直接保存到文件
- 保存文件的类:
NSFileHandle (读写二进制文件)和NSOutputStream NSFileManager (创建 删除 复制文件)
NSFileHandle
-(void)saveFile:(NSData *)data{
NSString *filePath = @"/Users/Apple/Desktop/111.hm"";
NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:filePath];
if(file == nil){
[data writeToFile:path atomically:YES];
}else{
[file seekToEndOfFile];
[file writeData:data];
[file closeFile];
}
}
NSOutputStream
@property(nonatomic,strong)NSOutputStream *stream;
self.stream = [NSOutputStream outputSteamToFileAtPath:@"/Users/Apple/Desktop/111.hm",append:YES];
[self.stream open];
[self.stream write:data.bytes maxLength:data.length];
[self.stream close];
断点续传
- 判断是否存在文件,如果文件不存,重新下载
- 如果文件存在
- 判断本地的文件大小=服务器文件大小 不需要下载
- 判断本地的文件大小<服务器文件大小 从当前位置开始下载
- 判断本地的文件大小>服务器文件大小 删除文件,重新下载
NSURLConnection的断点续传
是在消息循环机制上运行,如果在子线程,需要手动开启子线程的消息循环机制,故不推荐
@property(nonatomic,copy)NSString *filePath;
@property(nonatomic,copy)NSString *currentFileSize;
-(void)getServerFileInfo:(NSURL *)url{
NSURLRequest *request = [NSURLRequest requestWtihURL:url];
request.HTTPMethod = @"head";
NSURLResponse *response = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
self.currentFileSize = response.expectedContentLength;
self.filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:response.suggestedFilename];
}
-(long long)checkLocalFileInfo{
long long fileSize = 0;
NSFileManager *fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:self.filePath]){
NSDictionary *attrs = [fileManager attributesOfItemAtPath:self.selfPath error:NULL];
fileSize = attrs.fileSize
if(fileSize == self.expectedContentLength){
fileSize = -1;
}
if(fileSize > self.expectedContentLength){
fileSize = 0;
[fileManager removeItemAtPath:self.filePath error:NULL];
}
}
return fileSize;
}
-(void)downloadFile(NSURL *)url{
[[NSOperationQueue new] addOperationWithBlock:^{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]
[request setVale:[NSString stringWithFormat:@"bytes=%lld-",self.currentFileSize] forHTTPHeaderField:@"Range"];
NSURLConnection *con = [[NSURLConnecttion alloc]initWithRequest:request delegate:self];
[[NSRunLoop currentRunLoop] run];
}];
}
-(void)download:(NSString *)urlString successBlock:(void(^)(NSString *path))successBlock processBlock:(void(^)(float process))processBlock errorBlock:(void(^)(ESError *error))errorBlock{
self.successBlock = successBlock;
self.processBlock = processBlock;
self.errorBlock = errorBlock;
NSURL *url = [NSURL URLWithString:urlString];
[self getServerFileInfo:url];
self.currentFileSize = [self checkLocalFileInfo];
if(self.currentFileSize == -1){
if(self.successBlock){
dispatch_async(dispatch_get_main_queue(),^{
self.successBlock(self.filePath);
});
}
return;
}
[self downloadFile:url];
}
-(void)pause{
[self.conn cancel];
}
下载的回调
@property(noatomic,copy) void(^successBlock)(NSString *path);
@property(noatomic,copy) void(^processBlock)(float process);
@property(noatomic,copy) void(^errorBlock)(NSError *error);
if(self.processBlock){
self.pro cessBlock(process);
}
if(self.successBlock){
dispatch_async(dispatch_get_main_queue(),^{
self.successBlock(self.filePath);
});
}
if(self.errorBlock){
self.errorBlock(error);
}
绘制进度圆(UI内容)
-(void)drawRect:(CGRect)rect{
UIBezierPath *Path = [UIBezierPath bezierPath];
CGPoint center = CGPointMake(rect.size.width/2,rect.size.height/2);
CGFloat radius = MIS(center.x,center.y);
CGFloat startAngle = -M_PI_2;
CGFloat endAngle = 2 * M_PI * self.process + startAngle;
[path addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
path.lineWidth = 5 ;
path.lineCapStyle = kCGLineCapRound;
[[UIColor orangeColor] setStroke];
[path stroke];
}
下载操作的管理类
写一个单例模式的管理类,拥有一个操作缓存池
@property(noatomic,strong) NSMuatbleDictionary *downloaderCache;
-(NSMuatbleDictionary *)downloaderCache{
if(_downloaderCache == nil){
_downloaderCache = [NSMuatbleDictionary dictionaryWithCapacity:10];
}
return _downloaderCache;
}
if(self.downloaderCache[urlString]){
NSLog(@"正在下载了!");
return;
}else{
...
[self.downloaderCache setObject:downloader forKey:urlString];
[self.downloaderCache removeObjectForKey:urlString];
}
|