一、文件上传下载
1、小文件下载
直接用NSData的+ (id)dataWithContentsOfURL:(NSURL *)url;
利用NSURLConnection发送一个HTTP请求去下载
如果是下载图片,还可以利用SDWebImage框架
2、 HTTP Range
通过设置请求头Range可以指定每次从网路下载数据包的大小—–可以用于断点下载
[request setValue:[NSString stringWithFormat:@"bytes=%lld-",self.currentDataLength] forHTTPHeaderField:@"Range"];
1)Range示例
bytes=0-499 从0到499的头500个字节
bytes=500-999 从500到999的第二个500字节
bytes=500- 从500字节以后的所有字节
bytes=-500 最后500个字节
bytes=500-599,800-899 同时指定几个范围
2)Range小结
- 用于分隔
前面的数字表示起始字节数
后面的数组表示截止字节数,没有表示到末尾
用于分组,可以一次指定多个Range,不过很少用
第三方解压缩框架——SSZipArchive
Adding to your project
Add SSZipArchive.h, SSZipArchive.m, and minizip to your project.
Add the libz library to your target 需要引入libz.dylib框架
Usage
// Unzipping
NSString *zipPath = @"path_to_your_zip_file";
NSString *destinationPath = @"path_to_the_folder_where_you_want_it_unzipped";
[SSZipArchive unzipFileAtPath:zipPath toDestination:destinationPath];
// Zipping
NSString *zippedPath = @"path_where_you_want_the_file_created";
NSArray *inputPaths = [NSArray arrayWithObjects:
[[NSBundle mainBundle] pathForResource:@"photo1" ofType:@"jpg"],
[[NSBundle mainBundle] pathForResource:@"photo2" ofType:@"jpg"]
nil];
[SSZipArchive createZipFileAtPath:zippedPath withFilesAtPaths:inputPaths];
4、multipart/form-data格式小结 --文件上传
设置Post的请求头(key value)
/*Content-Type multipart/form-data; boundary=本次上传标示字符串(不能中文)*/
[request setValue:@"multipart/form-data;boundary=hisun" forHTTPHeaderField:@"Content-Type"];
The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/.
文件上传的请求体中包含的内容
请求参数
文件参数
--本次上传标示字符串(边界比请求头的boundary 增加--开头)
Content-Disposition: form-data; name="参数名"; filename="文件名"
Content-Type: MIMEType (文件类型)
文件具体数据
非文件参数
--本次上传标示字符串(--边界)
Content-Disposition: form-data; name="参数名称";
参数值
--边界–(结尾标记 )
结尾标记(--边界--)
代码块
zip 压缩文件夹
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [cachePath stringByAppendingPathComponent:@"images"];
NSString *zipPath = [cachePath stringByAppendingPathComponent:@"images.zip"];
NSLog(@"%@,%@",filePath,zipPath);
[SSZipArchive createZipFileAtPath:zipPath withContentsOfDirectory:filePath];
根据URL 获取mimeType
- (NSString *) mimeTypeWithUrl:(NSURL *)url{
NSURLResponse *response;
[NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:&response error:nil];
return response.MIMEType;
}
// NSString *mimetype = [self mimeTypeWithUrl:[NSURL fileURLWithPath:@"/Users/devzkn/Desktop/minion_02.png"]];
使用NSMutableURLRequest文件上传
#define HSBasicUrl @"http://127.0.0.1:8080/KNServer/"
#define HSUrl(name) [NSURL URLWithString:[NSString stringWithFormat:@"%@%@",HSBasicUrl,name]]
#define HSFileBoundary @"hisun"
#define HSFileEndedBounary [NSString stringWithFormat:@"--%@--",HSFileBoundary]
#define HSFileStartBoundary [NSString stringWithFormat:@"--%@",HSFileBoundary]
#define HSNewLine @"\r\n"
#define HSStringEncoding(str) [str dataUsingEncoding:NSUTF8StringEncoding]
#pragma mark - 文件上传
- (void)upload:(NSString*)fileName mimeType:(NSString *)mimeType fileData:(NSData*)fileData params:(NSDictionary*)params{
//设置请求体
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:HSUrl(@"upload")];
//准备请求体数据
NSMutableData *data =[NSMutableData data];
/*
请求体:
1)文件参数
--本次上传标示字符串(边界)
Content-Disposition: form-data; name="参数名"; filename="文件名"
Content-Type: MIMEType (文件类型)
文件具体数据
2)非文件参数
--本次上传标示字符串(边界)
Content-Disposition: form-data; name="参数名称"
参数值
3)边界–(结尾标记 )
*/
[data appendData:HSStringEncoding(HSFileStartBoundary)];//分界线
[data appendData:HSStringEncoding(HSNewLine)];
NSString *disposition = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"",@"file",fileName];
[data appendData:HSStringEncoding(disposition)];//参数名
[data appendData:HSStringEncoding(HSNewLine)];
NSString *mimeTypeStr = [NSString stringWithFormat:@"Content-Type:%@",mimeType];
[data appendData:HSStringEncoding(mimeTypeStr)];
[data appendData:HSStringEncoding(HSNewLine)];
[data appendData:HSStringEncoding(HSNewLine)];
[data appendData:fileData];
[data appendData:HSStringEncoding(HSNewLine)];
//设置非文件数据
[params enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
[data appendData:HSStringEncoding(HSFileStartBoundary)];//分界线
[data appendData:HSStringEncoding(HSNewLine)];
NSString *disposition = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"",key];
[data appendData:HSStringEncoding(disposition)];//参数名
[data appendData:HSStringEncoding(HSNewLine)];
[data appendData:HSStringEncoding(HSNewLine)];
[data appendData:HSStringEncoding([obj description])];
[data appendData:HSStringEncoding(HSNewLine)];
}];
//结尾
[data appendData:HSStringEncoding(HSFileEndedBounary)];
[data appendData:HSStringEncoding(HSNewLine)];
[request setHTTPBody:data];
[request setHTTPMethod:@"post"];
[request setValue:[NSString stringWithFormat:@"multipart/form-data;boundary=%@",HSFileBoundary] forHTTPHeaderField:@"Content-Type"];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSLog(@"%@,%@",response,[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]);
}];
}
NSURLSession-断点续传
- (NSURLSession *)session{
if (_session == nil) {
_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue] ];
}
return _session;
}
#pragma mark - 断点下载
- (IBAction)pause:(UIButton *)sender {
[sender setSelected:!sender.selected];
if (sender.selected) {
if (self.task == nil) {
if (self.resumeData) {
[self resumeDownLoad];//继续下载
}else{
[self startSessionWithConfiguration];//开始下载
}
}
}else{
[self pauseDownload];//暂停
}
}
#pragma mark - NSURLSessionDownloadDelegate 查看下载进度
- (void) startSessionWithConfiguration{
NSLog(@"%s----start ",__func__);
[self.circularProgressView setProgress:0];
[self.button setSelected:YES];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:HSURL(@"resources/videos/iPhoneSimulator6.1.sdk.zip")];
self.task = [self.session downloadTaskWithRequest:request];
[self.task resume];//执行任务
}
- (void)resumeDownLoad{
if (self.resumeData == nil) {
return;
}
NSLog(@"%s-----继续",__func__);
self.task = [self.session downloadTaskWithResumeData:self.resumeData];
[self.task resume];
self.resumeData = nil;
}
- (void)pauseDownload {
NSLog(@"%s------ 暂停",__func__);
if (self.task == nil) {
return;
}
/*
A completion handler that is called when the download has been successfully canceled.
If the download is resumable, the completion handler is provided with a resumeData object. Your app can later pass this object to a session’s downloadTaskWithResumeData: or downloadTaskWithResumeData:completionHandler: method to create a new task that resumes the download where it left off.即包含了创建链接的URL和连接的头信息(Range)
*/
HSweakself(weakself);
[self.task cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
weakself.resumeData = resumeData;
weakself.task = nil;
}];
}
/* Sent when a download task that has completed a download. The delegate should
* copy or move the file at the given location to a new location as it will be
* removed when the delegate message returns. URLSession:task:didCompleteWithError: will
* still be called.
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location{
NSString *filePath = HSCachePath(downloadTask.response.suggestedFilename);
NSLog(@"%s----%@ --%@ --%@",__func__,downloadTask.response,filePath,location.path);
//移动location文件到filePath
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager moveItemAtPath:location.path toPath:filePath error:nil];
}
/* Sent periodically to notify the delegate of download progress. */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
NSLog(@"%s----%@,bytesWritten:%lld,------totalBytesWritten:%lld,------totalBytesExpectedToWrite:%lld------%f%%",__func__,downloadTask,bytesWritten,totalBytesWritten,totalBytesExpectedToWrite,(double)totalBytesWritten*100.0/totalBytesExpectedToWrite);
[self.circularProgressView setProgress:(double)totalBytesWritten*1.0/totalBytesExpectedToWrite];
}
/* Sent when a download has been resumed. If a download failed with an
* error, the -userInfo dictionary of the error will contain an
* NSURLSessionDownloadTaskResumeData key, whose value is the resume
* data.
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{
NSLog(@"%s-----fileOffset:%lld,---expectedTotalBytes:%lld",__func__,fileOffset,expectedTotalBytes);
}
NSURLConnection断点下载
#pragma mark - 断点下载
- (IBAction)pause:(UIButton *)sender {
[sender setSelected:!sender.selected];
if (sender.selected) {//继续下载
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1:8080/MJServer/resources/videos/iPhoneSimulator6.1.sdk.zip"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//设置Range
[request setValue:[NSString stringWithFormat:@"bytes=%lld-",self.currentDataLength] forHTTPHeaderField:@"Range"];
NSLog(@"%@",[NSString stringWithFormat:@"bytes=%lld-",self.currentDataLength]);
self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
}else{//暂停下载
[self.connection cancel];
self.connection = nil;
}
}
#pragma mark - NSURLConnectionDataDelegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
self.response = (NSHTTPURLResponse*)response;
if (self.currentDataLength) {//断点之后的新请求,无需执行以下代码
return;
}
//创建一个和预期下载文件一样大小的文件到沙盒--以便多线程断点下载,的线程分工;----单线程断点下载只需创建一个空文件
NSString *filePath = HSCachePath([connection.currentRequest.URL lastPathComponent]);
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager createFileAtPath:filePath contents:nil attributes:nil];
//创建文件handle
self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
self.totalDataLength = response.expectedContentLength;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
self.currentDataLength += data.length;
// NSDictionary *dict = [self.response allHeaderFields];
// NSString *length = dict[@"Content-Length"];//获取预期长度
// NSString *length = self.response.expectedContentLength;
[self.circularProgressView setProgress:self.currentDataLength*1.0/self.totalDataLength];
[self.fileHandle seekToEndOfFile];
[self.fileHandle writeData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
[self.fileHandle closeFile];
self.currentDataLength =0;
}
作者:u011018979 发表于2017/7/10 11:48:25 原文链接
阅读:20 评论:0 查看评论