oss-android/ios-sdk 断点续传
前言
移动端现状
随着移动端设备的硬件水平的不断提高,如今的cpu,内存等方面都大大的超过了一般的pc电脑,因此在现今的程序中,合理的使用多线程去完成一些事情是非常有必要的。
多线程上传的好处
进一步占满网络资源。
进一步占满I/O资源。
实现原理
策略
oss有分片上传的功能,断点续传就是基于分片上传的几个api接口进行的封装,主要由InitiateMultipartUpload,UploadPart,CompleteMultipartUpload,AbortMultipartUpload,ListParts这几个组成。
流程
细节
断点续传是一个大任务,又3部分来完成,分别是获取uploadId,分片上传,完成上传,这一整个连续的步骤统一在一个线程中进行。
获取uploadId这块需要先对本地缓存文件进行获取,如未拿到,就会直接重新生成新的uploadId直接去进行分片上传,否则会对记录的id进行之前上传了多少片进行还原,继续原来的位置继续上传。
分片上传部分,采用多线程并发上传机制,目前线程开启数量最多5条,根据cpu的核数进行判断,如果核数<5
会采用核数进行配置, 分片的个数最多5000。
完成上传,对上传的part进行排序,需要按照自然顺序1~n 的顺序进行上传。
文件校验,通过文件的md5等其他信息进行校验,分片上传中每一片也会跟服务器做md5校验。
进度回调机制,目前进度回调算是最基础版,目前回调原理是根据每一个分片来回调的,即当分片上传成功回调一次。
使用方式
在本地持久保存断点记录的调用方式:
android:
", "", "", recordDirectory);\n // 设置上传过程回调\nrequest.setProgressCallback(new OSSProgressCallback() {\n @Override\n public void onProgress(ResumableUploadRequest request\n , long currentSize, long totalSize) {\n Log.d("resumableUpload", "currentSize: " + currentSize + " totalSize: " + totalSize);\n }\n});\nOSSAsyncTask resumableTask = oss.asyncResumableUpload(request\n , new OSSCompletedCallback() {\n @Override\n public void onSuccess(ResumableUploadRequest request, ResumableUploadResult result) {\n Log.d("resumableUpload", "success!");\n }\n \n @Override\n public void onFailure(ResumableUploadRequest request, ClientException clientExcepion\n , ServiceException serviceException) {\n // 异常处理\n }\n});","classes":null}" data-cke-widget-upcasted="1" data-cke-widget-keep-attr="0" data-widget="codeSnippet" class="cke_widget_element">String recordDirectory = Environment.getExternalStorageDirectory().getAbsolutePath() + "/oss_record/";
File recordDir = new File(recordDirectory);
// 要保证目录存在,如果不存在则主动创建
if (!recordDir.exists()) {
recordDir.mkdirs();
}
// 创建断点上传请求,参数中给出断点记录文件的保存位置,需是一个文件夹的绝对路径
ResumableUploadRequest request
= new ResumableUploadRequest("", "", "", recordDirectory);
// 设置上传过程回调
request.setProgressCallback(new OSSProgressCallback() {
@Override
public void onProgress(ResumableUploadRequest request
, long currentSize, long totalSize) {
Log.d("resumableUpload", "currentSize: " + currentSize + " totalSize: " + totalSize);
}
});
OSSAsyncTask resumableTask = oss.asyncResumableUpload(request
, new OSSCompletedCallback() {
@Override
public void onSuccess(ResumableUploadRequest request, ResumableUploadResult result) {
Log.d("resumableUpload", "success!");
}
@Override
public void onFailure(ResumableUploadRequest request, ClientException clientExcepion
, ServiceException serviceException) {
// 异常处理
}
});
ios:
;\nresumableUpload.objectKey = ;\nresumableUpload.partSize = 1024 * 1024;\nresumableUpload.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {\n NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);\n};\n \nresumableUpload.uploadingFileURL = [NSURL fileURLWithPath:];\nNSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];\nresumableUpload.recordDirectoryPath = cachesDir;//记录断点的文件路径\nOSSTask * resumeTask = [client resumableUpload:resumableUpload];\n[resumeTask continueWithBlock:^id(OSSTask *task) {\n if (task.error) {\n NSLog(@"error: %@", task.error);\n if ([task.error.domain isEqualToString:OSSClientErrorDomain]\n && task.error.code == OSSClientErrorCodeCannotResumeUpload) {\n // 该任务无法续传,需要获取新的uploadId重新上传\n }\n } else {\n NSLog(@"Upload file success");\n }\n return nil;\n}];","classes":null}" data-cke-widget-upcasted="1" data-cke-widget-keep-attr="0" data-widget="codeSnippet" class="cke_widget_element">// 获得UploadId进行上传,如果任务失败并且可以续传,利用同一个UploadId可以上传同一文件到同一个OSS上的存储对象
OSSResumableUploadRequest * resumableUpload = [OSSResumableUploadRequest new];
resumableUpload.bucketName = ;
resumableUpload.objectKey = ;
resumableUpload.partSize = 1024 * 1024;
resumableUpload.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
};
resumableUpload.uploadingFileURL = [NSURL fileURLWithPath:];
NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
resumableUpload.recordDirectoryPath = cachesDir;//记录断点的文件路径
OSSTask * resumeTask = [client resumableUpload:resumableUpload];
[resumeTask continueWithBlock:^id(OSSTask *task) {
if (task.error) {
NSLog(@"error: %@", task.error);
if ([task.error.domain isEqualToString:OSSClientErrorDomain]
&& task.error.code == OSSClientErrorCodeCannotResumeUpload) {
// 该任务无法续传,需要获取新的uploadId重新上传
}
} else {
NSLog(@"Upload file success");
}
return nil;
}];
性能统计
数据分析
android/ios 端的分片上传改为并发后的测试与之前对比,上传分片的网络请求速度 多线程 和
单线程是一样的使用时间,这个主要是取决于带宽速度, 多线程相较于单线程主要是提高了读取文件的io时间。数据如下:
分享:
喜欢
0
赠金笔
加载中,请稍候......
评论加载中,请稍候...
发评论
登录名: 密码: 找回密码 注册记住登录状态
昵 称:
评论并转载此博文
发评论
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。