IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> IOS开发之网络编程6(文件上传POST和下载HEAD) -> 正文阅读

[移动开发]IOS开发之网络编程6(文件上传POST和下载HEAD)

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];
	//设置post
	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];
//设置post
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{
	//bytesWritten 本次下载了多少字节
	//totalBytesWritten 总共下载了多少字节
	//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{
	//destinationURL下载文件的沙盒地址
}
//处理错误
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
	NSLog(@"下载出错%@",error)
}
  • NSURLConnectionDataDelegate
    NSURLConnectionDownloadDelegate继承自NSURLConnectionDataDelegate
//接受到响应头
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
	//记得写这个@property(nonatomic,assign)long long currentFileSize;
	self.currentFileSize = response.expectedContentlength;
}
//一点一点接受数据
//用一个NSMutableData存数据,记得重写他的get函数
//@property(nonatomic,strong)NSMutableData currentFileSize;
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
	//记得写这个@property(nonatomic,assign)long long currentFileSize;
	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"";
	//文件创建,文件不存在返回的是nil
	NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath:filePath];
	//
	if(file == nil){
	//data直接写入
	[data writeToFile:path atomically:YES];
	}else{
	//文件指针移动到文件尾
	[file seekToEndOfFile];
	//文件指针移动到指定位置
	//[file seekToFileOffset:<#(unsigned long long)>];
	//写入文件
	[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;
	//&response用于参数传值
	[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
	//当前文件大小
	self.currentFileSize = response.expectedContentLength;
	//文件路径
	self.filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:response.suggestedFilename];
}
//获取本地文件的大小,和服务器文件比较
//判断文件是否存在,不存在0
-(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{
	//NSOperation多线程
	[[NSOperationQueue new] addOperationWithBlock:^{
	NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]
	//修改请求头
    //Range:bytes=x-y 从x下载到y
    //Range:bytes=x- 从x下载到最后
    //Range:bytes=-y 从头下载到y
	[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){
	//需要回到主线程GCD
	dispatch_async(dispatch_get_main_queue(),^{
		self.successBlock(self.filePath);
	});
}
if(self.errorBlock){
	self.errorBlock(error);
}

绘制进度圆(UI内容)

-(void)drawRect:(CGRect)rect{
	//Drawing code
	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];
}
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-31 15:33:43  更:2021-08-31 15:36:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年5日历 -2025/5/4 1:49:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码