This topic describes how to use multipart upload.

Initialize a multipart upload task

The following code provides an example on how to initialize a multipart upload task:

__block NSString * uploadId = nil;
__block NSMutableArray * partInfos = [NSMutableArray new];
NSString * uploadToBucket = @"<bucketName>";
// objectKey is equivalent to objectName and indicates the complete path of the object that you want to upload to OSS. The path must include the file extension of the object. For example, you can set objectKey to abc/efg/123.jpg.
NSString * uploadObjectkey = @"<objectKey>";
OSSInitMultipartUploadRequest * init = [OSSInitMultipartUploadRequest new];
init.bucketName = uploadToBucket;
init.objectKey = uploadObjectkey;
// init.contentType = @"application/octet-stream";
OSSTask * initTask = [client multipartUploadInit:init];
[initTask waitUntilFinished];
if (! initTask.error) {
    OSSInitMultipartUploadResult * result = initTask.result;
    uploadId = result.uploadId;
} else {
    NSLog(@"multipart upload failed, error: %@", initTask.error);
    return;
}
Note
  • OSSInitMultipartUploadRequest is used to specify the name of the object you want to upload and the name of the bucket to which to upload the object.
  • The response to multipartUploadInit contains the upload ID. The upload ID is the unique identifier of the multipart upload task.

Upload parts.

The following code provides an example on how to upload parts:

NSString * filePath = [docDir stringByAppendingPathComponent:@"***"];
// Specify the object you want to upload.
int chuckCount = *;
// Specify the number of parts.
uint64_t offset = fileSie/chuckCount;
// Specify the size of each part.
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;
    }
}
			

The preceding code uses uploadPart to upload each part.

Notice
  • An upload ID and a part number must be specified for each multipart upload request.
  • If you use uploadPart, each part (except for the last part) must be larger than 100 KB in size. However, the UploadPart API operation does not check the size of each part immediately after the part is uploaded. This API operation checks the part size only when multipart upload is complete.
  • The part number ranges from 1 to 10000. If a part number is beyond this range, OSS returns the InvalidArgument error code.
  • When each part is uploaded, the stream is directed to the starting position of the uploaded part.
  • After each part is uploaded, OSS returns a response that contains the ETag value of the part. If the ETag value and the MD5 value of the part are the same, you must combine the ETag value with the part number into a PartETag and save the PartETag for subsequent upload of parts.

Complete the multipart upload task

In the following code, the partInfos field value indicates the list of PartETags saved during multipart upload. OSS verifies the validity of each part after OSS receives the partInfos field value. When all the parts are verified to be valid, OSS combines them into a complete object.

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];
			

You can set the servercallback parameter to complete the multipart upload request. A callback request is sent to the specified server address after the multipart upload task is complete. You can view the servercallback result in result.serverReturnJsonString of the response.

OSSCompleteMultipartUploadRequest * complete = [OSSCompleteMultipartUploadRequest new];
complete.bucketName = @"<bucketName>";
complete.objectKey = @"<objectKey>";
complete.uploadId = uploadId;
complete.partInfos = partInfos;
complete.callbackParam = @{
                          @"callbackUrl": @"<server address>",
                          @"callbackBody": @"<test>"
                          };
complete.callbackVar = @{
                        @"var1": @"value1",
                        @"var2": @"value2"
                        };
OSSTask * completeTask = [client completeMultipartUpload:complete];
[[completeTask continueWithBlock:^id(OSSTask *task) {
    if (! task.error) {
        OSSCompleteMultipartUploadResult * result = task.result;
        NSLog(@"server call back return : %@", result.serverReturnJsonString);
    } else {
        // ...
    }
    return nil;
}] waitUntilFinished];
Note You can attach the Content-MD5 field value to the upload request to check whether the object uploaded to OSS is consistent with the local file. The OSS server helps you with the MD5 verification. The upload is successful only when the MD5 value of the object received by the OSS server is the same as the Content-MD5 field value. This method can ensure the consistency of uploaded object.

The following code provides an example on how to configure MD5 verification:

OSSUploadPartRequest * uploadPart = [OSSUploadPartRequest new];
uploadPart.bucketName = TEST_BUCKET;
uploadPart.uploadId = uploadId;
....
uploadPart.contentMd5 = [OSSUtil fileMD5String:filepath];
				

List parts

The following code provides an example on how to call the listParts method to obtain all uploaded parts of an upload event:

OSSListPartsRequest * listParts = [OSSListPartsRequest new];
listParts.bucketName = @"<bucketName>";
listParts.objectKey = @"<objectkey>";
listParts.uploadId = @"<uploadid>";

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;
}];
			
Notice By default, if a bucket contains more than 1,000 parts that are uploaded through multipart upload, OSS returns the first 1,000 parts. In the response, the IsTruncated field is set to false and NextPartNumberMarker is returned to indicate the next starting position to continue reading data.

Cancel a multipart upload event

The following code provides an example on how to cancel a multipart upload request that is mapped to the specified upload ID:

OSSAbortMultipartUploadRequest * abort = [OSSAbortMultipartUploadRequest new];
abort.bucketName = @"<bucketName>";
abort.objectKey = @"<objectKey>";
abort.uploadId = uploadId;

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;
}