All Products
Search
Document Center

Object Storage Service:Perform multipart upload by using OSS SDK for iOS

Last Updated:Aug 28, 2024

Object Storage Service (OSS) provides the multipart upload feature. This feature allows you to split a large object into multiple parts and upload the parts separately. After the upload is complete, you can call the CompleteMultipartUpload operation to combine these parts into a complete object.

Usage notes

  • Before you run the sample code in this topic, you must create an OSSClient instance by using methods such as using a custom domain name or Security Token Service (STS). For more information, see Initialization.

    Note

    When you initialize an OSSClient instance, specify an endpoint that maps to the region of the bucket.

  • To upload an object, you must have the oss:PutObject permission. For more information, see Attach a custom policy to a RAM user.

Multipart upload process

To perform a multipart upload, perform the following steps:

  1. Split the object that you want to upload into parts.

  2. Call the InitiateMultipartUpload operation to initiate a multipart upload task.

  3. Call the UploadPart operation to upload the parts one by one or in parallel.

  4. Call the CompleteMultipartUpload operation to complete the upload task.

image

Before you start a multipart upload task, take note of the following items:

  • Each part except the last part must be at least 100 KB in size. Otherwise, the CompleteMultipartUpload operation fails.

  • The position of a part in the object is determined by its part number that you specify during the upload process. Parts do not have to be uploaded in sequence and can be uploaded concurrently.

    To concurrently upload parts, you need to specify an appropriate concurrency level based on your network conditions and device loads. A higher concurrency level does not necessarily mean a faster upload speed. We recommend that you increase the part size when network conditions are stable and decrease the part size when network conditions are unstable.

  • By default, if you upload the parts of an object but do not call the CompleteMultipartUpload operation to combine these parts, the uploaded parts are not automatically deleted. You can call the AbortMultipartUpload operation to terminate the upload task and delete the parts. For more information about how to automatically delete the uploaded parts, see Lifecycle rules based on the last modified time.

Complete sample code of a multipart upload task

The following sample code provides a complete example on how to implement a multipart upload task:

__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 by using multipart upload

Note

The preceding complete sample code implements a multipart upload task by following the multipart upload process. The following sample code encapsulates the preceding complete sample code to allow you to upload a local file in parts simply by using MultipartUploadRequest.

The following sample code provides an example on how to upload a local file by using multipart upload:

// 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

The following sample code provides an example on how to list all uploaded parts of a multipart upload task by using listParts:

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

By default, if a bucket contains more than 1,000 parts that are uploaded by using multipart upload, OSS returns the first 1,000 parts. In the response, the value of the IsTruncated field is false and NextPartNumberMarker is returned to indicate the start position of the next list operation.

Cancel a multipart upload task

The following sample code provides an example on how to cancel a multipart upload task that has a specific upload ID:

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

  • For the complete sample code that is used to perform multipart upload, visit GitHub.

  • A multipart upload involves three API operations. For more information about the operations, see the following topics:

  • For more information about the API operation that you can call to list uploaded parts, see ListParts.

  • For more information about the API operation that you can call to cancel a multipart upload task, see AbortMultipartUpload.