当前位置: 移动技术网 > 移动技术>移动开发>IOS > iOS大文件的分片上传和断点上传的实现代码

iOS大文件的分片上传和断点上传的实现代码

2019年07月24日  | 移动技术网移动技术  | 我要评论

今天小编抽空给大家分享一些大文件的上传的问题!断点续传和分片上传。因为文件过大(比如1g以上),必须要考虑上传过程网络中断的情况。http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件切片(分块),但这不是我们现在说的重点,我们要做的事是保证在网络中断后1g的文件已上传的那部分在下次网络连接时不必再重传。所以我们本地在上传的时候,要将大文件进行分片,比如分成1024*1024b,即将大文件分成1m的片进行上传,服务器在接收后,再将这些片合并成原始文件,这就是分片的基本原理。断点续传要求本地要记录每一片的上传的状态,我通过三个状态进行了标记(wait loading finish),当网络中断,再次连接后,从断点处进行上传。服务器通过文件名、总片数判断该文件是否已全部上传完成。

下面来说细节:

1、首先获取文件(音视频、图片)

分两种情况,一种是在相册库里直接获取,一种是调用相机。如果是通过uiimagepickerview来获取(细节不详述,网上一大堆),我们会发现当你选定一个视频的时候,会出现图1的压缩页面,最后我们的app获取的视频就是这个经过压缩后的视频(不是视频库里的原始视频,这里有个注意点,操作完该压缩视频后记得释放,系统不会帮你释放的,需要你手动来操作,下面会说到),然后通过uiimagepickerview的协议方法中的- (void)imagepickercontroller:(uiimagepickercontroller*)picker didfinishpickingmediawithinfo:(nsdictionary*)info获取视频的info

fileinfo = {
uiimagepickercontrollermediatype = "public.movie";
uiimagepickercontrollermediaurl = "file:///private/var/mobile/containers/data/application/2aae9e44-0e6d-4499-9ac3-93d44d8342ea/tmp/trim.f36ec46c-4219-43c8-96a7-fa7141ab64d2.mov";
uiimagepickercontrollerreferenceurl = "assets-library://asset/asset.mov?id=deda9406-3223-4f87-abb2-98fb5f5eb9c4&ext=mov";
}

uiimagepickercontrollermediatype是选取文件的类型,如kuttypeimage,kuttypemovie。这里注意一下movie和video的区别,一个是有声音的视频文件,一个是没有声音的视频文件,当然还有audio是只有声音没有视频。uiimagepickercontrollermediaurl是视频的url(如果是相机拍摄的,那么这个就是原始拍摄得到的视频;如果是在相册库里选择的,那就是压缩之后生成的视频),注意这个url不指向相册库,通过这个url你可以操作这个视频如删除,拷贝等,可以获取压缩后的视频的大小。uiimagepickercontrollerreferenceurl是一个指向相册的url,官方的解释是an nsurl that references an asset in the assetslibrary framework,通过这个url,你可以获取视频的所有信息,包括文件名,缩略图,时长等(通过alassetslibrary里的assetslibraryassetforurl:referenceurlresultblock:)。

如果是相机拍摄的,注意两个保存方法:图片保存到相册

assetslibrarywriteimagedatatosavedphotosalbum:uiimagejpegrepresentation([infovalueforkey:uiimagepickercontrolleroriginalimage],(cgfloat)1.0)metadata:nilcompletionblock: failureblock:

高保真压缩图片的方法nsdata * uiimagejpegrepresentation ( uiimage *image, cgfloat compressionquality)

视频保存到相册:assetslibrarywritevideoatpathtosavedphotosalbum:mediaurl completionblock:failureblock:

到这里,我们就获取了所有需要的文件以及文件信息。下面要做的就是将文件分片。

2、将获取到的文件分片

首先,我将获取到的文件保存在这这样一个类中

@interface cnfile :nsobject
@property(nonatomic,copy)nsstring* filetype;//image or movie
@property(nonatomic,copy)nsstring* filepath;//文件在app中路径
@property(nonatomic,copy)nsstring* filename;//文件名
@property(nonatomic,assign)nsintegerfilesize;//文件大小
@property (nonatomic,assign)nsintegertrunks;//总片数
@property(nonatomic,copy)nsstring* fileinfo;
@property(nonatomic,strong)uiimage* fileimage;//文件缩略图
@property(nonatomic,strong) nsmutablearray* filearr;//标记每片的上传状态
@end

这样我们就可以对每一个cnfile对象进行操作了。

-(void)readdatawithchunk:(nsinteger)chunk file:(cnfile*)file{

总片数的获取方法:

intoffset =1024*1024;(每一片的大小是1m)
nsintegerchunks = (file.filesize%1024==0)?((int)(file.filesize/1024*1024)):((int)(file.filesize/(1024*1024) +1));
nslog(@"chunks = %ld",(long)chunks);

将文件分片,读取每一片的数据:

nsdata* data;
nsfilehandle*readhandle = [nsfilehandlefilehandleforreadingatpath:file.filepath];
[readhandleseektofileoffset:offset * chunk];
data = [readhandlereaddataoflength:offset];
}

这样我们就获取了每一片要上传的数据,然后询问服务器,该片是否已经存在

(方法-(void)ifhavedata:(nsdata*)data withchunk:(nsinteger)chunk file:(cnfile*)file)

,如果存在,令chunk+1,重复上面的方法读取下一片,直到服务器不存在该片,那么上传该片数据。在这个方法中注意设置该chunk的上传状态(wait loading finish),这将关系到本地判断该文件是否已全部上传完成。

下一步就是上传的过程:

-(void)uploaddata:(nsdata*) data withchunk:(nsinteger) chunk file:(cnfile*)file;

在服务器返回该片上传成功后,我们要做的事有很多:

1)先将已经成功上传的本片的flag置finish

[file.filearrreplaceobjectatindex:chunk withobject:@“finish"];

2)查看是否所有片的flag都已经置finish,如果都已经finishi,说明该文件上传完成,那么删除该文件,上传下一个文件或者结束。

for(nsintegerj =0; j
if(j == chunks || ((j == chunks -1)&&([file.filearr[j]isequaltostring:@"finish"])))
[medeletefile:file.filepath];
[mereadnextfile];
}

3)如果没有都finish,那么看本地下一chunk对用的flag是否是wait

nslog(@"查看第%ld片的状态",chunk+1);
for(nsintegeri = chunk+1;i < chunks;i++)
{
nsstring* flag = [file.filearrobjectatindex:i];
if([flagisequaltostring:@"wait"]) {
[mereaddatawithchunk:ifilename:filenamefile:file];
break;
}
}

在第2、3步之间可以有一个 2.5)判断是否暂停上传

if(me.ispause ==yes)
{
//将目前读到了第几个文件的第几片保存到本地
[selfsaveprogresswithchunk:chunk file:file];
return;
}

这个操作实际上和上传过程中断网是一样的,为了断点续传,在断网或者暂停的时候,我们要将目前的进度保存起来,以便下次上传时略过前面已置finish的片。

然后还有一个问题,如果我们就这样线性的一片一片上传,实际上失去了分片上传的意义,应该结合多线程,使分片上传过程并发执行,同时上传多片,这样就提高了上传效率,并充分利用了网络带宽。

dispatch_async(dispatch_queue_t queue, ^{
[mereaddatawithchunk: chunk];
})

最后注意一下,每上传完一个视频,去设置里看看你的app占用的存储空间有没有增大哦,如果你没有处理那个生成的压缩视频,你会发现你的app的空间占用量是很大的。

总结

以上所述是小编给大家介绍的ios大文件的分片上传和断点上传,希望对大家有所帮助

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网