iOS开发中文件的上传和下载功能的基本实现-备用
感谢大神分享
这篇文章主要介绍了iOS开发中文件的上传和下载功能的基本实现,并且下载方面讲到了大文件的多线程断点下载,需要的朋友可以参考下
文件的上传
说明:文件上传使用的时POST请求,通常把要上传的数据保存在请求体中。本文介绍如何不借助第三方框架实现iOS开发中得文件上传。
由于过程较为复杂,因此本文只贴出部分关键代码。
主控制器的关键代码:
#import "YYViewController.h"
#define YYEncode(str) [str dataUsingEncoding:NSUTF8StringEncoding]
@interface YYViewController ()
@end
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)upload:(NSString *)name filename:(NSString *)filename mimeType:(NSString *)mimeType data:(NSData *)data parmas:(NSDictionary *)params
{
// 文件上传
NSURL *url = [NSURL URLWithString:@"http://192.168.1.200:8080/YYServer/upload"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
// 设置请求体
NSMutableData *body = [NSMutableData data];
/***************文件参数***************/
// 参数开始的标志
[body appendData:YYEncode(@"--YY\r\n")];
// name : 指定参数名(必须跟服务器端保持一致)
// filename : 文件名
NSString *disposition = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", name, filename];
[body appendData:YYEncode(disposition)];
NSString *type = [NSString stringWithFormat:@"Content-Type: %@\r\n", mimeType];
[body appendData:YYEncode(type)];
[body appendData:YYEncode(@"\r\n")];
[body appendData:data];
[body appendData:YYEncode(@"\r\n")];
/***************普通参数***************/
[params enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
// 参数开始的标志
[body appendData:YYEncode(@"--YY\r\n")];
NSString *disposition = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", key];
[body appendData:YYEncode(disposition)];
[body appendData:YYEncode(@"\r\n")];
[body appendData:YYEncode(obj)];
[body appendData:YYEncode(@"\r\n")];
}];
/***************参数结束***************/
// YY--\r\n
[body appendData:YYEncode(@"--YY--\r\n")];
request.HTTPBody = body;
// 设置请求头
// 请求体的长度
[request setValue:[NSString stringWithFormat:@"%zd", body.length] forHTTPHeaderField:@"Content-Length"];
// 声明这个POST请求是个文件上传
[request setValue:@"multipart/form-data; boundary=YY" forHTTPHeaderField:@"Content-Type"];
// 发送请求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (data) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
NSLog(@"%@", dict);
} else {
NSLog(@"上传失败");
}
}];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Socket 实现断点上传
//apache-tomcat-6.0.41/conf/web.xml 查找 文件的 mimeType
// UIImage *image = [UIImage imageNamed:@"test"];
// NSData *filedata = UIImagePNGRepresentation(image);
// [self upload:@"file" filename:@"test.png" mimeType:@"image/png" data:filedata parmas:@{@"username" : @"123"}];
// 给本地文件发送一个请求
NSURL *fileurl = [[NSBundle mainBundle] URLForResource:@"itcast.txt" withExtension:nil];
NSURLRequest *request = [NSURLRequest requestWithURL:fileurl];
NSURLResponse *repsonse = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&repsonse error:nil];
// 得到mimeType
NSLog(@"%@", repsonse.MIMEType);
[self upload:@"file" filename:@"itcast.txt" mimeType:repsonse.MIMEType data:data parmas:@{
@"username" : @"999",
@"type" : @"XML"}];
}
@end
补充说明:
文件上传请求数据格式

部分文件的MIMEType

多线程断点下载
说明:本文介绍多线程断点下载。项目中使用了苹果自带的类,实现了同时开启多条线程下载一个较大的文件。因为实现过程较为复杂,所以下面贴出完整的代码。
实现思路:下载开始,创建一个和要下载的文件大小相同的文件(如果要下载的文件为100M,那么就在沙盒中创建一个100M的文件,然后计算每一段的下载量,开启多条线程下载各段的数据,分别写入对应的文件部分)。

项目中用到的主要类如下:

完成的实现代码如下:
主控制器中的代码:
#import "YYFileMultiDownloader.h"
@interface YYViewController ()
@property (nonatomic, strong) YYFileMultiDownloader *fileMultiDownloader;
@end
- (YYFileMultiDownloader *)fileMultiDownloader
{
if (!_fileMultiDownloader) {
_fileMultiDownloader = [[YYFileMultiDownloader alloc] init];
// 需要下载的文件远程URL
_fileMultiDownloader.url = @"http://192.168.1.200:8080/MJServer/resources/jre.zip";
// 文件保存到什么地方
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filepath = [caches stringByAppendingPathComponent:@"jre.zip"];
_fileMultiDownloader.destPath = filepath;
}
return _fileMultiDownloader;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.fileMultiDownloader start];
}
@end
自定义一个基类
#import <Foundation/Foundation.h>
@interface YYFileDownloader : NSObject
{
BOOL _downloading;
}
/**
* 所需要下载文件的远程URL(连接服务器的路径)
*/
@property (nonatomic, copy) NSString *url;
/**
* 文件的存储路径(文件下载到什么地方)
*/
@property (nonatomic, copy) NSString *destPath;
/**
* 是否正在下载(有没有在下载, 只有下载器内部才知道)
*/
@property (nonatomic, readonly, getter = isDownloading) BOOL downloading;
/**
* 用来监听下载进度
*/
@property (nonatomic, copy) void (^progressHandler)(double progress);
/**
* 开始(恢复)下载
*/
- (void)start;
/**
* 暂停下载
*/
- (void)pause;
@end
YYFileDownloader.m文件
@implementation YYFileDownloader
@end
下载器类继承自YYFileDownloader这个类
YYFileSingDownloader.h文件
@interface YYFileSingleDownloader : YYFileDownloader
/**
* 开始的位置
*/
@property (nonatomic, assign) long long begin;
/**
* 结束的位置
*/
@property (nonatomic, assign) long long end;
@end
YYFileSingDownloader.m文件
@interface YYFileSingleDownloader() <NSURLConnectionDataDelegate>
/**
* 连接对象
*/
@property (nonatomic, strong) NSURLConnection *conn;
/**
* 写数据的文件句柄
*/
@property (nonatomic, strong) NSFileHandle *writeHandle;
/**
* 当前已下载数据的长度
*/
@property (nonatomic, assign) long long currentLength;
@end
- (NSFileHandle *)writeHandle
{
if (!_writeHandle) {
_writeHandle = [NSFileHandle fileHandleForWritingAtPath:self.destPath];
}
return _writeHandle;
}
/**
* 开始(恢复)下载
*/
- (void)start
{
NSURL *url = [NSURL URLWithString:self.url];
// 默认就是GET请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置请求头信息
NSString *value = [NSString stringWithFormat:@"bytes=%lld-%lld", self.begin + self.currentLength, self.end];
[request setValue:value forHTTPHeaderField:@"Range"];
self.conn = [NSURLConnection connectionWithRequest:request delegate:self];
_downloading = YES;
}
/**
* 暂停下载
*/
- (void)pause
{
[self.conn cancel];
self.conn = nil;
_downloading = NO;
}
#pragma mark - NSURLConnectionDataDelegate 代理方法
/**
* 1. 当接受到服务器的响应(连通了服务器)就会调用
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
}
/**
* 2. 当接受到服务器的数据就会调用(可能会被调用多次, 每次调用只会传递部分数据)
*/
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 移动到文件的尾部
[self.writeHandle seekToFileOffset:self.begin + self.currentLength];
// 从当前移动的位置(文件尾部)开始写入数据
[self.writeHandle writeData:data];
// 累加长度
self.currentLength += data.length;
// 打印下载进度
double progress = (double)self.currentLength / (self.end - self.begin);
if (self.progressHandler) {
self.progressHandler(progress);
}
}
/**
* 3. 当服务器的数据接受完毕后就会调用
*/
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 清空属性值
self.currentLength = 0;
// 关闭连接(不再输入数据到文件中)
[self.writeHandle closeFile];
self.writeHandle = nil;
}
/**
* 请求错误(失败)的时候调用(请求超时\断网\没有网, 一般指客户端错误)
*/
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
}
@end
设计多线程下载器(利用HMFileMultiDownloader能开启多个线程同时下载一个文件)
一个多线程下载器只下载一个文件
YYFileMultiDownloader.h文件
@interface YYFileMultiDownloader : YYFileDownloader
@end
YYFileMultiDownloader.m文件
#import "YYFileSingleDownloader.h"
#define YYMaxDownloadCount 4
@interface YYFileMultiDownloader()
@property (nonatomic, strong) NSMutableArray *singleDownloaders;
@property (nonatomic, assign) long long totalLength;
@end
- (void)getFilesize
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.url]];
request.HTTPMethod = @"HEAD";
NSURLResponse *response = nil;
#warning 这里要用异步请求
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
self.totalLength = response.expectedContentLength;
}
- (NSMutableArray *)singleDownloaders
{
if (!_singleDownloaders) {
_singleDownloaders = [NSMutableArray array];
// 获得文件大小
[self getFilesize];
// 每条路径的下载量
long long size = 0;
if (self.totalLength % YYMaxDownloadCount == 0) {
size = self.totalLength / YYMaxDownloadCount;
} else {
size = self.totalLength / YYMaxDownloadCount + 1;
}
// 创建N个下载器
for (int i = 0; i<YYMaxDownloadCount; i++) {
YYFileSingleDownloader *singleDownloader = [[YYFileSingleDownloader alloc] init];
singleDownloader.url = self.url;
singleDownloader.destPath = self.destPath;
singleDownloader.begin = i * size;
singleDownloader.end = singleDownloader.begin + size - 1;
singleDownloader.progressHandler = ^(double progress){
NSLog(@"%d --- %f", i, progress);
};
[_singleDownloaders addObject:singleDownloader];
}
// 创建一个跟服务器文件等大小的临时文件
[[NSFileManager defaultManager] createFileAtPath:self.destPath contents:nil attributes:nil];
// 让self.destPath文件的长度是self.totalLengt
NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:self.destPath];
[handle truncateFileAtOffset:self.totalLength];
}
return _singleDownloaders;
}
/**
* 开始(恢复)下载
*/
- (void)start
{
[self.singleDownloaders makeObjectsPerformSelector:@selector(start)];
_downloading = YES;
}
/**
* 暂停下载
*/
- (void)pause
{
[self.singleDownloaders makeObjectsPerformSelector:@selector(pause)];
_downloading = NO;
}
@end
补充说明:如何获得将要下载的文件的大小?

iOS开发中文件的上传和下载功能的基本实现-备用的更多相关文章
- JavaWeb中文件的上传和下载
JavaWeb中文件的上传和下载 转自: JavaWeb学习总结(五十)——文件上传和下载 - 孤傲苍狼 - 博客园https://www.cnblogs.com/xdp-gacl/p/4200090 ...
- SpringMVC+Ajax实现文件批量上传和下载功能实例代码
需求: 文件批量上传,支持断点续传. 文件批量下载,支持断点续传. 使用JS能够实现批量下载,能够提供接口从指定url中下载文件并保存在本地指定路径中. 服务器不需要打包. 支持大文件断点下载.比如下 ...
- Java中文件的上传与下载
文件的上传与下载主要用到两种方法: 1.方法一:commons-fileupload.jar commons-io.jar apache的commons-fileupload实现文件上传,下载 [u ...
- 009 spring boot中文件的上传与下载
一:任务 1.任务 文件的上传 文件的下载 二:文件的上传 1.新建一个对象 FileInfo.java package com.cao.dto; public class FileInfo { pr ...
- iOS开发篇-AFNetworking 上传和下载
最近用到了关于AFNetworking的上传和下载问题,顺便写到博客中,以供大家参考和研究. //下载NSURLSessionConfiguration *configuration = [NSURL ...
- C#实现FTP文件的上传、下载功能、新建目录以及文件的删除
本来这篇博文应该在上周就完成的,可无奈,最近工作比较忙,没有时间写,所以推迟到了今天.可悲的是,今天也没有太多的时间,所以决定给大家贴出源码,不做详细的分析说明,如果有不懂的,可以给我留言,我们共同讨 ...
- Struts中文件的上传与下载
前面学到的用组件去上传 前台: 1.post表单提交 2.表单类型 multipart/form-data 3.intput type=file 后台: Apach提供的FileUpload组件 核心 ...
- docker容器中文件的上传与下载
原文地址:传送门 1.上传文件 docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH [OPTIONS]:保持源目标中的链接,例: docker cp ...
- JSP中文件的上传于下载演示样例
一.文件上传的原理 1.文件上传的前提: a.form表单的method必须是post b.form表单的enctype必须是multipart/form-da ...
随机推荐
- 在同一上机器上建立两个SVN服务
最快的三步: 1,SVNADMIN CREATE NAME 2, 改写CONF目录下的相关三个文件. 3,重写一个SVN的启动脚本,指定这个SVN不同的目录及端口号. [general] ### Th ...
- Sublime Text2不自动打开最近的项目
1.首选项 2.设置默认 "hot_exit": false, "remember_open_files": false, 这两个值改成false就可以了
- 【转】s3c2440 按键驱动 — 字符设备
原文网址:http://www.xuebuyuan.com/632893.html 主机:VM - redhat 9.0 开发板:FL2440,linux-2.6.12 arm-linux-gcc:3 ...
- 【转】VS2013中如何解决error C4996: 'fopen'问题
原文网址:http://jingyan.baidu.com/article/ce436649fd61543773afd32e.html 今天编写控制台应用程序时出现如下错误 error C4996: ...
- 2015.9.11模拟赛 codevs 4159【hzwer的迷の数列】
题目描述 Description hzwer找了一个人畜无害的迷の数列…… 现在hzwer希望对这个数列进行一些操作,请你来回答hzwer的问题. 操作一:查询第i个数的大小 操作二:把第i个数的大小 ...
- 瑞柏匡丞_免费app开发是否可行
随着移动互联时代的到来,手机APP软件开发已成为一大商机.当众人纷纷涌入这一领域“淘金”时,有人则做起了“卖水”的生意.无需编程知识和开发成本,只需要输入简单的文字指令,三分钟的时间就可以生成一个AP ...
- 【初学者常见问题】一脚踏入protected埋下的陷阱
受保护的(protected)——声明该成员的类的子类可以访问这个类的成员(但有一定的限制),并且,声明该成员的包内部的任何类也可以访问这个成员 protected修饰符参考:http://www.3 ...
- 关于使用axis调用webservice接口方法
1.概述: 我们有时候会调用webserviec接口,我们向接口发送请求参数,从接口接收返回值. 2.形式: package client; import org.apache.axis.client ...
- 《Programming Massively Parallel Processors》Chapter5 习题解答
自己做的部分习题解答,因为时间关系,有些马虎,也不全面,欢迎探讨或指出错误 5.1 Consider the matrixaddition in Exercise 3.1. Can one use s ...
- Spring + mybatis整合方案总结 结合实例应用
Spring + mybatis整合实例应用 项目结构图 (Spring3.0.2 +mybatis3.0.4) 方案一: 通过配置文件整合Spring和mybatis 应用数据库 -- --数据库 ...