对象存储OSS-分片上传
程序员文章站
2024-03-19 22:45:04
...
文章目录
对象存储OSS-分片上传
什么是分片上传
当使用简单上传(PutObject)功能来上传较大的文件到OSS的时候,如果上传的过程中出现了网络错误,会出现上传失败,重试必须从文件起始位置上传。针对这种情况,OSS提供了分片上传(Multipart Upload)来达到断点续传的效果。
顾名思义,分片上传就是将要上传的文件分成多个数据块(OSS里又称之为Part)来分别上传,上传完成之后再调用OSS的接口将这些Part组合成一个Object。
分片上传的实用场景
一般传输大文件的时候使用分片上传,比如大的视频点播文件等。
分片上传的三个步骤
1、初始化一个分片上传事件
略…
2、上传分片
这里有两个步骤,1将文件分片,2将分片的文件上传。分片的大小可根据整个文件的大小来合理的设置分片数量。例如,有一个文件是5个G,分片数量设置为10,即将一个5个G的文件分10次上传,每次上传0.5个G。
3、完成分片上传
略…
代码实现
上传部分代码
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//7、初始化OSSInitMultipartUploadRequest
__block NSString * uploadId = nil;
__block NSMutableArray *partInfos = [NSMutableArray new];
NSString *uploadToBucket = [VHOSSManager sharedManager].federationToken.bucketName;
NSString *uploadObjectkey = [NSString stringWithFormat:@"demand/%@%@",uplodFile.fileMD5,uplodFile.MIMEType];
OSSInitMultipartUploadRequest * init = [OSSInitMultipartUploadRequest new];
init.bucketName = uploadToBucket;
init.objectKey = uploadObjectkey;
OSSTask * initTask = [[VHOSSManager sharedManager].client multipartUploadInit:init];
[initTask waitUntilFinished];
if (!initTask.error) {
OSSInitMultipartUploadResult *result = initTask.result;
uploadId = result.uploadId;
} else {
OSSLogDebug(@"multipart upload failed, error: %@", initTask.error);
return;
}
//8、分片上传
uint64_t offset = uplodFile.totalBytes / chuckCount;//每个分片大小
__block uint64_t mostUploadSize = 0;
for (int i = 1; i <= chuckCount; i++) {
@autoreleasepool {
OSSUploadPartRequest * uploadPart = [OSSUploadPartRequest new];
uploadPart.bucketName = uploadToBucket;
uploadPart.objectkey = uploadObjectkey;
uploadPart.uploadId = uploadId;
uploadPart.partNumber = i; // part number start from 1
uploadPart.uploadPartProgress = ^(int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) { //本次回调上传的长度,当前总共上传的长度,一共需要上传的长度
mostUploadSize += bytesSent;
if (progressCallback) {
progressCallback(uplodFile,i,totalBytesSent,totalBytesExpectedToSend,mostUploadSize,uplodFile.totalBytes);
}
};
NSFileHandle* readHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
[readHandle seekToFileOffset:offset * (i -1)];
NSData* data = [readHandle readDataOfLength:offset];
uploadPart.uploadPartData = data;
OSSTask * uploadPartTask = [[VHOSSManager sharedManager].client uploadPart:uploadPart];
[uploadPartTask waitUntilFinished];
if (!uploadPartTask.error) {
OSSUploadPartResult * result = uploadPartTask.result;
uint64_t fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:uploadPart.uploadPartFileURL.absoluteString error:nil] fileSize];
[partInfos addObject:[OSSPartInfo partInfoWithPartNum:i eTag:result.eTag size:fileSize]];
} else {
OSSLogDebug(@"upload part error: %@", uploadPartTask.error);
return;
}
}
}
//9、完成分片上传
OSSCompleteMultipartUploadRequest * complete = [OSSCompleteMultipartUploadRequest new];
complete.bucketName = uploadToBucket;
complete.objectKey = uploadObjectkey;
complete.uploadId = uploadId;
complete.partInfos = partInfos;
OSSTask * completeTask = [[VHOSSManager sharedManager].client completeMultipartUpload:complete];
[[completeTask continueWithBlock:^id(OSSTask *task) {
dispatch_async(dispatch_get_main_queue(), ^{
if (!task.error) {
//OSSCompleteMultipartUploadResult *result = task.result;
if (successCallback) {
successCallback(nil);
}
} else {
if (failedCallback) {
failedCallback(nil,task.error);
}
}
OSSLogDebug(@"upload result error: %@", task.error);
});
return nil;
}] waitUntilFinished];
});
-
上传分片的时候记录mostUploadSize,本地累计
-
分片策略可以自己定义,上面使用的是均分每个片进行上传
分片上传是将每个分片分别上传,每次上传文件的某一片的数据,每次上传读取对应分片的数据:
NSFileHandle* readHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
[readHandle seekToFileOffset:offset * (i -1)];
NSData* data = [readHandle readDataOfLength:offset];
uploadPart.uploadPartData = data;
offset是每个分片的长度,i是从1开始的
第1个分片的数据是将数据seek到0的位置,读取长度为offset的数据进行上传,
第2个分片的数据是将数据seek到1的位置,然后读取长度offset的数据进行上传,
第i个分片…
问题
1、分片上传,上传进度怎么处理?
分片上传Api
/**
分片上传进度回调
@param fileInfo 当前上传的文件
@param partNum 当前第N个分片(分片数是从1开始)
@param partUploadedSize 当前分片已上传文件大小
@param partTotalSize 当前分片文件大小
@param uploadTotalSize 当前总共上传的文件大小
@param mostTotalSize 文件总大小
*/
typedef void (^MultipartUploadProgressCallback) (VHUploadFileInfo* _Nullable fileInfo, NSInteger partNum,int64_t partUploadedSize, int64_t partTotalSize, int64_t uploadTotalSize,int64_t mostTotalSize);
可以回调每个分片的上传进度,也可以回调整个文件的上传进度,具体可见上传部分代码实现。
注意事项
- uploadPart 要求除最后一个 Part 外,其他的 Part 大小都要大于100KB。
心得
OSS很强大,各种功能都有。
小文件能不使用分片就别使用分片,除非是大文件,分片上传的思想是很好的,但是要注意使用场景。
上一篇: Vue.js之组件注册