Object Storage Service (OSS) は、マルチパートアップロード機能を提供します。この機能を使用すると、ラージオブジェクトを複数のパートに分割し、それぞれを個別にアップロードできます。すべてのパートがアップロードされた後、CompleteMultipartUpload 操作を呼び出してパートを結合し、完全なオブジェクトを作成できます。このプロセスにより、再開可能なアップロードが可能になります。
注意事項
このトピックでは、中国 (杭州) リージョンのパブリックエンドポイントを使用します。OSS と同じリージョンにある他の Alibaba Cloud サービスから OSS にアクセスする場合は、内部エンドポイントを使用してください。OSS のリージョンとエンドポイントの詳細については、「リージョンとエンドポイント」をご参照ください。
このトピックでは、OSS エンドポイントを使用して OSSClient インスタンスを作成します。カスタムドメイン名または Security Token Service (STS) を使用して OSSClient インスタンスを作成する場合は、「初期化 (C SDK)」をご参照ください。
InitiateMultipartUpload、UploadPart、CompleteMultipartUpload 操作を含むマルチパートアップロードプロセスを完了するには、
oss:PutObject権限が必要です。詳細については、「RAM ユーザーへのカスタム権限の付与」をご参照ください。
マルチパートアップロードのプロセス
マルチパートアップロードを使用してオブジェクトをアップロードするには、次の手順を実行します。
マルチパートアップロードイベントの初期化
oss_init_multipart_upload メソッドを呼び出します。このメソッドは、OSS によって作成されたグローバルに一意のアップロード ID を返します。
パートのアップロード
oss_upload_part_from_file を呼び出してパートをアップロードします。
説明特定の uploadId に対して、パート番号は完全なオブジェクト内でのパートの位置を識別します。既存のパートと同じパート番号で新しいパートをアップロードすると、既存のパートは上書きされます。
OSS は、受信したパートデータの MD5 ハッシュをレスポンスの ETag ヘッダーに含めます。
OSS は、アップロードされたデータの MD5 ハッシュを計算し、SDK によって計算された MD5 ハッシュと比較します。2 つのハッシュが一致しない場合、OSS は InvalidDigest エラーコードを返します。
マルチパートアップロードの完了
すべてのパートをアップロードした後、oss_complete_multipart_upload メソッドを呼び出して、それらを結合し、完全なファイルを作成します。
マルチパートアップロードの完全な例
次の例は、マルチパートアップロードの完全なプロセスを示しています。
#include "oss_api.h"
#include "aos_http_io.h"
#include <sys/stat.h>
/* yourEndpoint を、バケットが配置されているリージョンのエンドポイントに設定します。 たとえば、バケットが中国 (杭州) リージョンにある場合、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。 */
const char *endpoint = "yourEndpoint";
/* バケット名 (例: examplebucket) を入力します。 */
const char *bucket_name = "examplebucket";
/* オブジェクトのフルパスを入力します。 パスにバケット名を含めることはできません。 たとえば、exampledir/exampleobject.txt と入力します。 */
const char *object_name = "exampledir/exampleobject.txt";
/* ローカルファイルのフルパスを入力します。 */
const char *local_filename = "yourLocalFilename";
/* yourRegion を、バケットが配置されているリージョンに設定します。 たとえば、バケットが中国 (杭州) リージョンにある場合、リージョンを cn-hangzhou に設定します。 */
const char *region = "yourRegion";
void init_options(oss_request_options_t *options)
{
options->config = oss_config_create(options->pool);
/* aos_string_t 型を char* 文字列で初期化します。 */
aos_str_set(&options->config->endpoint, endpoint);
/* 環境変数からアクセス認証情報を取得します。 このコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。 */
aos_str_set(&options->config->access_key_id, getenv("OSS_ACCESS_KEY_ID"));
aos_str_set(&options->config->access_key_secret, getenv("OSS_ACCESS_KEY_SECRET"));
// 次の 2 つのパラメーターを設定します。
aos_str_set(&options->config->region, region);
options->config->signature_version = 4;
/* CNAME を使用して OSS にアクセスするかどうかを指定します。 値 0 は、CNAME が使用されないことを意味します。 */
options->config->is_cname = 0;
/* タイムアウト期間などのネットワークパラメーターを設定します。 */
options->ctl = aos_http_controller_create(options->pool, 0);
}
int64_t get_file_size(const char *file_path)
{
int64_t filesize = -1;
struct stat statbuff;
if(stat(file_path, &statbuff) < 0){
return filesize;
} else {
filesize = statbuff.st_size;
}
return filesize;
}
int main(int argc, char *argv[])
{
/* プログラムのエントリポイントで、aos_http_io_initialize メソッドを呼び出して、ネットワークやメモリなどのグローバルリソースを初期化します。 */
if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
exit(1);
}
/* メモリ管理用のメモリプール (pool)。 apr_pool_t と同等です。 実装コードは apr ライブラリにあります。 */
aos_pool_t *pool;
/* 新しいメモリプールを作成します。 2 番目のパラメーターは NULL で、プールが他のメモリプールから継承しないことを示します。 */
aos_pool_create(&pool, NULL);
/* オプションを作成して初期化します。 このパラメーターには、endpoint、access_key_id、access_key_secret、is_cname、curl などのグローバル構成が含まれます。 */
oss_request_options_t *oss_client_options;
/* メモリプール内のオプションにメモリを割り当てます。 */
oss_client_options = oss_request_options_create(pool);
/* クライアントオプション oss_client_options を初期化します。 */
init_options(oss_client_options);
/* パラメーターを初期化します。 */
aos_string_t bucket;
aos_string_t object;
oss_upload_file_t *upload_file = NULL;
aos_string_t upload_id;
aos_table_t *headers = NULL;
aos_table_t *complete_headers = NULL;
aos_table_t *resp_headers = NULL;
aos_status_t *resp_status = NULL;
aos_str_set(&bucket, bucket_name);
aos_str_set(&object, object_name);
aos_str_null(&upload_id);
headers = aos_table_make(pool, 1);
complete_headers = aos_table_make(pool, 1);
int part_num = 1;
/* マルチパートアップロードを初期化し、アップロード ID を取得します。 */
resp_status = oss_init_multipart_upload(oss_client_options, &bucket, &object, &upload_id, headers, &resp_headers);
/* マルチパートアップロードが正常に初期化されたかどうかを確認します。 */
if (aos_status_is_ok(resp_status)) {
printf("Init multipart upload succeeded, upload_id:%.*s\n",
upload_id.len, upload_id.data);
} else {
printf("Init multipart upload failed, upload_id:%.*s\n",
upload_id.len, upload_id.data);
}
/* パートをアップロードします。 */
int64_t file_length = 0;
int64_t pos = 0;
aos_list_t complete_part_list;
oss_complete_part_content_t* complete_content = NULL;
char* part_num_str = NULL;
char* etag = NULL;
aos_list_init(&complete_part_list);
file_length = get_file_size(local_filename);
while(pos < file_length) {
upload_file = oss_create_upload_file(pool);
aos_str_set(&upload_file->filename, local_filename);
upload_file->file_pos = pos;
pos += 100 * 1024;
upload_file->file_last = pos < file_length ? pos : file_length;
resp_status = oss_upload_part_from_file(oss_client_options, &bucket, &object, &upload_id, part_num++, upload_file, &resp_headers);
/* パート番号と ETag を保存します。 */
complete_content = oss_create_complete_part_content(pool);
part_num_str = apr_psprintf(pool, "%d", part_num-1);
aos_str_set(&complete_content->part_number, part_num_str);
etag = apr_pstrdup(pool,
(char*)apr_table_get(resp_headers, "ETag"));
aos_str_set(&complete_content->etag, etag);
aos_list_add_tail(&complete_content->node, &complete_part_list);
if (aos_status_is_ok(resp_status)) {
printf("Multipart upload part from file succeeded\n");
} else {
printf("Multipart upload part from file failed\n");
}
}
/* マルチパートアップロードを完了します。 */
resp_status = oss_complete_multipart_upload(oss_client_options, &bucket, &object, &upload_id,
&complete_part_list, complete_headers, &resp_headers);
/* マルチパートアップロードが完了したかどうかを確認します。 */
if (aos_status_is_ok(resp_status)) {
printf("Complete multipart upload from file succeeded, upload_id:%.*s\n",
upload_id.len, upload_id.data);
} else {
printf("Complete multipart upload from file failed\n");
}
/* メモリプールを解放します。 これにより、リクエスト中に各リソースに割り当てられたメモリが解放されます。 */
aos_pool_destroy(pool);
/* 以前に割り当てられたグローバルリソースを解放します。 */
aos_http_io_deinitialize();
return 0;
}oss_complete_multipart_upload 操作を呼び出すときは、各パートの ETag 値を提供する必要があります。これらの値は、次の 2 つの方法のいずれかで取得できます。
各パートをアップロードすると、レスポンスにそのパートの ETag 値が含まれます。この値を保存して後で使用できます。上記の例ではこの方法を使用しています。
oss_list_upload_part 操作を呼び出して、以前にアップロードされたパートの ETag 値を取得します。
マルチパートアップロードイベントの中止
次のコードは、マルチパートアップロードイベントを中止する方法を示しています。
#include "oss_api.h"
#include "aos_http_io.h"
/* yourEndpoint を、バケットが配置されているリージョンのエンドポイントに設定します。 たとえば、バケットが中国 (杭州) リージョンにある場合、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。 */
const char *endpoint = "yourEndpoint";
/* バケット名を指定します。 たとえば、examplebucket です。 */
const char *bucket_name = "examplebucket";
/* オブジェクトのフルパスを指定します。 フルパスにバケット名を含めることはできません。 たとえば、exampledir/exampleobject.txt です。 */
const char *object_name = "exampledir/exampleobject.txt";
/* yourRegion を、バケットが配置されているリージョンに設定します。 たとえば、バケットが中国 (杭州) リージョンにある場合、リージョンを cn-hangzhou に設定します。 */
const char *region = "yourRegion";
void init_options(oss_request_options_t *options)
{
options->config = oss_config_create(options->pool);
/* aos_string_t 型を char* 文字列で初期化します。 */
aos_str_set(&options->config->endpoint, endpoint);
/* 環境変数からアクセス認証情報を取得します。 このコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。 */
aos_str_set(&options->config->access_key_id, getenv("OSS_ACCESS_KEY_ID"));
aos_str_set(&options->config->access_key_secret, getenv("OSS_ACCESS_KEY_SECRET"));
// 次の 2 つのパラメーターを設定します。
aos_str_set(&options->config->region, region);
options->config->signature_version = 4;
/* CNAME を使用して OSS にアクセスするかどうかを指定します。 0 は、CNAME が使用されないことを示します。 */
options->config->is_cname = 0;
/* タイムアウト期間などのネットワークパラメーターを設定します。 */
options->ctl = aos_http_controller_create(options->pool, 0);
}
int main(int argc, char *argv[])
{
/* プログラムエントリで aos_http_io_initialize メソッドを呼び出して、ネットワークやメモリなどのグローバルリソースを初期化します。 */
if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
exit(1);
}
/* メモリ管理用のメモリプール (pool) は apr_pool_t と同等です。 その実装コードは apr ライブラリにあります。 */
aos_pool_t *pool;
/* 新しいメモリプールを作成します。 2 番目のパラメーターは NULL で、新しいメモリプールが別のメモリプールから継承しないことを示します。 */
aos_pool_create(&pool, NULL);
/* オプションを作成して初期化します。 このパラメーターには、endpoint、access_key_id、access_key_secret、is_cname、curl などのグローバル構成情報が含まれます。 */
oss_request_options_t *oss_client_options;
/* メモリプール内のオプションにメモリを割り当てます。 */
oss_client_options = oss_request_options_create(pool);
/* クライアントオプション oss_client_options を初期化します。 */
init_options(oss_client_options);
/* パラメーターを初期化します。 */
aos_string_t bucket;
aos_string_t object;
aos_string_t upload_id;
aos_table_t *headers = NULL;
aos_table_t *resp_headers = NULL;
aos_status_t *resp_status = NULL;
aos_str_set(&bucket, bucket_name);
aos_str_set(&object, object_name);
aos_str_null(&upload_id);
/* マルチパートアップロードを初期化して、アップロード ID (upload_id) を取得します。 */
resp_status = oss_init_multipart_upload(oss_client_options, &bucket, &object, &upload_id, headers, &resp_headers);
/* マルチパートアップロードが正常に初期化されたかどうかを確認します。 */
if (aos_status_is_ok(resp_status)) {
printf("Init multipart upload succeeded, upload_id:%.*s\n",
upload_id.len, upload_id.data);
} else {
printf("Init multipart upload failed, upload_id:%.*s\n",
upload_id.len, upload_id.data);
}
/* マルチパートアップロードを中止します。 */
resp_status = oss_abort_multipart_upload(oss_client_options, &bucket, &object, &upload_id, &resp_headers);
/* マルチパートアップロードが正常に中止されたかどうかを確認します。 */
if (aos_status_is_ok(resp_status)) {
printf("Abort multipart upload succeeded, upload_id::%.*s\n",
upload_id.len, upload_id.data);
} else {
printf("Abort multipart upload failed\n");
}
/* メモリプールを解放します。 これにより、リクエスト中にリソースに割り当てられたメモリが解放されます。 */
aos_pool_destroy(pool);
/* 以前に割り当てられたグローバルリソースを解放します。 */
aos_http_io_deinitialize();
return 0;
}マルチパートアップロードイベントが中止されると、そのアップロード ID は他の操作には使用できなくなります。アップロードされたパートも削除されます。
関連ドキュメント
マルチパートアップロードの完全なコードサンプルは、「GitHub サンプル」をご参照ください。
マルチパートアップロードには 3 つの API 操作が含まれます。操作の詳細については、次のトピックをご参照ください。
マルチパートアップロードイベントの中止の詳細については、「AbortMultipartUpload」をご参照ください。