文件上传与下载

文件下载

如果文件比较小,下载方式会比较多

  • 直接用NSData的+ (id)dataWithContentsOfURL:(NSURL *)url;
  • 利用NSURLConnection发送一个HTTP请求去下载
  • 如果是下载图片,还可以利用SDWebImage框架

大文件下载

  • 方案一:利用NSURLConnection和它的代理方法

1.发送一个请求

1
2
3
4
5
6
// 1.URL
NSURL *url = [NSURL URLWithString:@"http://localhost:8080/MJServer/resources/videos.zip"];
// 2.请求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3.下载(创建完conn对象后,会自动发起一个异步请求)
[NSURLConnection connectionWithRequest:request delegate:self];

2.在代理方法中处理服务器返回的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
在接收到服务器的响应时:
1.创建一个空的文件
2.用一个句柄对象关联这个空的文件,目的是:方便后面用句柄对象往文件后面写数据
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// 文件路径
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filepath = [caches stringByAppendingPathComponent:@"videos.zip"];
// 创建一个空的文件 到 沙盒中
NSFileManager *mgr = [NSFileManager defaultManager];
[mgr createFileAtPath:filepath contents:nil attributes:nil];
// 创建一个用来写数据的文件句柄
self.writeHandle = [NSFileHandle fileHandleForWritingAtPath:filepath];
}
/**
在接收到服务器返回的文件数据时,利用句柄对象往文件的最后面追加数据
*/
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 移动到文件的最后面
[self.writeHandle seekToEndOfFile];
// 将数据写入沙盒
[self.writeHandle writeData:data];
}
/**
在所有数据接收完毕时,关闭句柄对象
*/
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 关闭文件
[self.writeHandle closeFile];
self.writeHandle = nil;
}

注意点:千万不能用NSMutableData来拼接服务器返回的数据

3.断点续传

通过设置请求头Range可以指定每次从网路下载数据包的大小
Range示例
bytes=0-499 从0到499的头500个字节
bytes=500-999 从500到999的第二个500字节
bytes=500- 从500字节以后的所有字节

bytes=-500 最后500个字节
bytes=500-599,800-899 同时指定几个范围
Range小结:
-用于分隔,前面的数字表示起始字节数,后面的数组表示截止字节数,没有表示到末尾,用于分组,可以一次指定多个Range,不过很少用

  • 方案二:NSURLConnection发送异步请求的方法

1.block形式 - 除开大文件下载以外的操作,都可以用这种形式

1
2
3
4
5
6
7
8
9
10
11
12
[NSURLConnection sendAsynchronousRequest:<#(NSURLRequest *)#> queue:<#(NSOperationQueue *)#> completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
}];
```
>>2.代理形式 - 一般用在大文件下载
>>```objectivec
// 1.URL
NSURL *url = [NSURL URLWithString:@"http://localhost:8080/MJServer/login?username=123&pwd=123"];
// 2.请求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3.下载(创建完conn对象后,会自动发起一个异步请求)
[NSURLConnection connectionWithRequest:request delegate:self];
  • 方案三:NSURLSession

1.使用步骤

  • 获得NSURLSession对象
  • 利用NSURLSession对象创建对应的任务(Task)
  • 开始任务([task resume])

2.获得NSURLSession对象

1
2
3
[NSURLSession sharedSession]
NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSOperationQueue mainQueue]];

3.任务类型

NSURLSessionDataTask

用途:用于非文件下载的GET\POST请求

1
2
3
4
5
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request];
NSURLSessionDataTask *task = [self.session dataTaskWithURL:url];
NSURLSessionDataTask *task = [self.session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//download something ...
}];

NSURLSessionDownloadTask

用途:用于文件下载(小文件、大文件)

1
2
3
4
5
NSURLSessionDownloadTask *task = [self.session downloadTaskWithRequest:request];
NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:url];
NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
//download something ...
}];

4、下载大文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration defaultSessionConfiguration];
// 1.得到session对象
NSURLSession *session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 2.创建一个下载task
NSURL *url = [NSURL URLWithString:@"http://localhost:8080/MJServer/resources/test.mp4"];
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url];
// 3.开始任务
[task resume];
// 如果给下载任务设置了completionHandler这个block,也实现了下载的代理方法,优先执行block
#pragma mark - NSURLSessionDownloadDelegate
/**
* 下载完毕后调用
*
* @param location 临时文件的路径(下载好的文件)
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
// location : 临时文件的路径(下载好的文件)
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// response.suggestedFilename : 建议使用的文件名,一般跟服务器端的文件名一致
NSString *file = [caches stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
// 将临时文件剪切或者复制Caches文件夹
NSFileManager *mgr = [NSFileManager defaultManager];
// AtPath : 剪切前的文件路径
// ToPath : 剪切后的文件路径
[mgr moveItemAtPath:location.path toPath:file error:nil];
}
/**
* 恢复下载时调用
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
// ....
}
/**
* 每当下载完(写完)一部分时就会调用(可能会被调用多次)
*
* @param bytesWritten 这次调用写了多少
* @param totalBytesWritten 累计写了多少长度到沙盒中了
* @param totalBytesExpectedToWrite 文件的总长度
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
double progress = (double)totalBytesWritten / totalBytesExpectedToWrite;
NSLog(@"下载进度---%f", progress);
}

文件上传

文件上传的步骤
1.设置请求头

目的:告诉服务器请求体里面的内容并非普通的参数,而是包含了文件参数

1
[request setValue:@"multipart/form-data; boundary=heima" forHTTPHeaderField:@"Content-Type"];

2.设置请求体

作用:存放参数(文件参数和非文件参数)

非文件参数

1
2
3
4
5
[body appendData:HMEncode(@"--heima\r\n")];
[body appendData:HMEncode(@"Content-Disposition: form-data; name=\"username\"\r\n")];
[body appendData:HMEncode(@"\r\n")];
[body appendData:HMEncode(@"张三")];
[body appendData:HMEncode(@"\r\n")];

文件参数

1
2
3
4
5
6
[body appendData:HMEncode(@"--heima\r\n")];
[body appendData:HMEncode(@"Content-Disposition: form-data; name=\"file\"; filename=\"test123.png\"\r\n")];
[body appendData:HMEncode(@"Content-Type: image/png\r\n")];
[body appendData:HMEncode(@"\r\n")];
[body appendData:imageData];
[body appendData:HMEncode(@"\r\n")];

结束标记 :参数结束的标记

1
[body appendData:HMEncode(@"--heima--\r\n")];

文件的MIMEType

如何获得文件的MIMEType

1.百度搜索

2.查找服务器下面的某个xml文件
apache-tomcat-6.0.41\conf\web.xml

3.加载文件时通过Reponse获得

1
2
3
4
5
6
7
8
9
10
- (NSString *)MIMEType:(NSURL *)url
{
// 1.创建一个请求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 2.发送请求(返回响应)
NSURLResponse *response = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
// 3.获得MIMEType
return response.MIMEType;
}

4.通过C语言函数

1
2
3
4
5
6
7
8
9
10
11
12
13
+ (NSString *)mimeTypeForFileAtPath:(NSString *)path
{
if (![[NSFileManager alloc] init] fileExistsAtPath:path]) {
return nil;
}
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)[path pathExtension], NULL);
CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType);
CFRelease(UTI);
if (!MIMEType) {
return @"application/octet-stream";
}
return NSMakeCollectable(MIMEType);
}

文件解压缩

1.技术方案

1).第三方框架:SSZipArchive
2).依赖的动态库:libz.dylib

2.压缩

1).第一个方法

1
2
3
4
5
/**
zipFile :产生的zip文件的最终路径
directory : 需要进行的压缩的文件夹路径
*/
[SSZipArchive createZipFileAtPath:zipFile withContentsOfDirectory:directory];

2.第二个方法

1
2
3
4
5
6
/**
zipFile :产生的zip文件的最终路径
files : 这是一个数组,数组里面存放的是需要压缩的文件的路径
files = @[@"/Users/apple/Destop/1.png", @"/Users/apple/Destop/3.txt"]
*/
[SSZipArchive createZipFileAtPath:zipFile withFilesAtPaths:files];

3.解压缩

1
2
3
4
5
/**
zipFile :需要解压的zip文件的路径
dest : 解压到什么地方
*/
[SSZipArchive unzipFileAtPath:zipFile toDestination:dest];