Multipart upload lets you split a large object into parts, upload them separately or in parallel, and then call CompleteMultipartUpload to combine the parts into a complete object.
Usage notes
-
Create an OSSClient instance by using a custom domain name or Security Token Service (STS) as described in Initialization.
NoteSpecify an endpoint that matches the bucket's region.
-
You must have the
oss:PutObjectpermission. Attach a custom policy to a RAM user.
Multipart upload process
To perform a multipart upload:
-
Split the object into parts.
-
Call InitiateMultipartUpload to initiate the upload task.
-
Call UploadPart to upload parts sequentially or in parallel.
-
Call CompleteMultipartUpload to complete the upload.
Usage notes:
-
Each part except the last must be at least 100 KB. Otherwise, CompleteMultipartUpload fails.
-
A part's position in the object is determined by the part number you specify. Parts can be uploaded in any order and concurrently.
Set the concurrency level based on your network conditions and device loads. Higher concurrency does not always mean faster uploads. Use larger parts when the network is stable and smaller parts when it is unstable.
-
Uploaded parts are not automatically deleted if you do not call CompleteMultipartUpload. Call AbortMultipartUpload to terminate the task and delete parts, or configure Lifecycle rules based on the last modified time for automatic cleanup.
Complete sample code
The following code implements a multipart upload:
__block NSString * uploadId = nil;
__block NSMutableArray * partInfos = [NSMutableArray new];
// Specify the name of the bucket. Example: examplebucket.
NSString * uploadToBucket = @"examplebucket";
// Specify the full path of the object. Example: exampledir/exampleobject.txt. Do not include the bucket name in the full path.
NSString * uploadObjectkey = @"exampledir/exampleobject.txt";
// Use OSSInitMultipartUploadRequest to specify the name of the uploaded object and the name of the bucket in which the object is stored.
OSSInitMultipartUploadRequest * init = [OSSInitMultipartUploadRequest new];
init.bucketName = uploadToBucket;
init.objectKey = uploadObjectkey;
// init.contentType = @"application/octet-stream";
// The response to multipartUploadInit contains the upload ID. The upload ID is the unique ID of the multipart upload task.
OSSTask * initTask = [client multipartUploadInit:init];
[initTask waitUntilFinished];
if (!initTask.error) {
OSSInitMultipartUploadResult * result = initTask.result;
uploadId = result.uploadId;
// Cancel the multipart upload task or list uploaded parts based on the upload ID.
// If you want to cancel a multipart upload task based on the upload ID, obtain the upload ID after you call the InitiateMultipartUpload operation to initiate the multipart upload task.
// If you want to list the uploaded parts in a multipart upload task based on the upload ID, obtain the upload ID after you call the InitiateMultipartUpload operation to initiate the multipart upload task but before you call the CompleteMultipartUpload operation to complete the multipart upload task.
//NSLog(@"UploadId": %@, uploadId);
} else {
NSLog(@"multipart upload failed, error: %@", initTask.error);
return;
}
// Specify the object that you want to upload.
NSString * filePath = @"<filepath>";
// Query the size of the object.
uint64_t fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil] fileSize];
// Specify the number of parts.
int chuckCount = 10;
// Specify the part size.
uint64_t offset = fileSize/chuckCount;
for (int i = 1; i <= chuckCount; i++) {
OSSUploadPartRequest * uploadPart = [OSSUploadPartRequest new];
uploadPart.bucketName = uploadToBucket;
uploadPart.objectkey = uploadObjectkey;
uploadPart.uploadId = uploadId;
uploadPart.partNumber = i; // part number start from 1
NSFileHandle* readHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
[readHandle seekToFileOffset:offset * (i -1)];
NSData* data = [readHandle readDataOfLength:offset];
uploadPart.uploadPartData = data;
OSSTask * uploadPartTask = [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 {
NSLog(@"upload part error: %@", uploadPartTask.error);
return;
}
}
OSSCompleteMultipartUploadRequest * complete = [OSSCompleteMultipartUploadRequest new];
complete.bucketName = uploadToBucket;
complete.objectKey = uploadObjectkey;
complete.uploadId = uploadId;
complete.partInfos = partInfos;
OSSTask * completeTask = [client completeMultipartUpload:complete];
[[completeTask continueWithBlock:^id(OSSTask *task) {
if (!task.error) {
OSSCompleteMultipartUploadResult * result = task.result;
// ...
} else {
// ...
}
return nil;
}] waitUntilFinished];
Upload a local file in parts
The preceding code follows the step-by-step multipart upload process. The following code uses MultipartUploadRequest to simplify local file uploads.
The following code uploads a local file in parts:
// Specify the name of the bucket. Example: examplebucket.
NSString *bucketName = @"examplebucket";
// Specify the full path of the object. Example: exampledir/exampleobject.txt. Do not include the bucket name in the full path.
NSString *objectKey = @"exampledir/exampleobject.txt";
OSSMultipartUploadRequest * multipartUploadRequest = [OSSMultipartUploadRequest new];
multipartUploadRequest.bucketName = bucketName;
multipartUploadRequest.objectKey = objectKey;
// Specify the part size. The default part size is 256 KB.
multipartUploadRequest.partSize = 1024 * 1024;
multipartUploadRequest.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
NSLog(@"progress: %lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
};
multipartUploadRequest.uploadingFileURL = [[NSBundle mainBundle] URLForResource:@"wangwang" withExtension:@"zip"];
OSSTask * multipartTask = [client multipartUpload:multipartUploadRequest];
[[multipartTask continueWithBlock:^id(OSSTask *task) {
if (task.error) {
NSLog(@"error: %@", task.error);
} else {
NSLog(@"Upload file success");
}
return nil;
}] waitUntilFinished];
List uploaded parts
Call listParts to list all parts uploaded in a multipart upload task.
OSSListPartsRequest * listParts = [OSSListPartsRequest new];
// Specify the name of the bucket. Example: examplebucket.
listParts.bucketName = @"examplebucket";
// Specify the full path of the object. Example: exampledir/exampleobject.txt. Do not include the bucket name in the full path.
listParts.objectKey = @"exampledir/exampleobject.txt";
// Specify the upload ID. You can obtain the upload ID from the response to the InitiateMultipartUpload operation. You must obtain the upload ID before you call the CompleteMultipartUpload operation to complete the multipart upload task.
listParts.uploadId = @"0004B999EF518A1FE585B0C9****";
OSSTask * listPartTask = [client listParts:listParts];
[listPartTask continueWithBlock:^id(OSSTask *task) {
if (!task.error) {
NSLog(@"list part result success!");
OSSListPartsResult * listPartResult = task.result;
for (NSDictionary * partInfo in listPartResult.parts) {
NSLog(@"each part: %@", partInfo);
}
} else {
NSLog(@"list part result error: %@", task.error);
}
return nil;
}];
// waitUntilFinished blocks execution of the current thread but does not block the task progress.
// [listPartTask waitUntilFinished];
If more than 1,000 parts exist, OSS returns only the first 1,000. In the response, IsTruncated is false and NextPartNumberMarker indicates where the next listing starts.
Cancel a multipart upload task
The following code cancels a multipart upload by UploadId.
OSSAbortMultipartUploadRequest * abort = [OSSAbortMultipartUploadRequest new];
// Specify the name of the bucket. Example: examplebucket.
abort.bucketName = @"examplebucket";
// Specify the full path of the object. Example: exampledir/exampleobject.txt. Do not include the bucket name in the full path.
abort.objectKey = @"exampledir/exampleobject.txt";
// Specify the upload ID. You can obtain the upload ID from the response to the InitiateMultipartUpload operation.
abort.uploadId = @"0004B999EF518A1FE585B0C9****";
OSSTask * abortTask = [client abortMultipartUpload:abort];
[abortTask waitUntilFinished];
if (!abortTask.error) {
OSSAbortMultipartUploadResult * result = abortTask.result;
uploadId = result.uploadId;
} else {
NSLog(@"multipart upload failed, error: %@", abortTask.error);
return;
}
// waitUntilFinished blocks execution of the current thread but does not block the task progress.
// [abortTask waitUntilFinished];
References
-
Complete multipart upload sample code is available on GitHub.
-
A complete multipart upload involves three API operations. The details are as follows:
-
For more information about the API operation to initialize a multipart upload event, see InitiateMultipartUpload.
-
For more information about the API operation to upload a part, see UploadPart.
-
For more information about the API operation to complete a multipart upload, see CompleteMultipartUpload.
-
-
List uploaded parts: ListParts.
-
Cancel a multipart upload task: AbortMultipartUpload.