0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Windows の C++ で OCI Object Storage を操作する

Last updated at Posted at 2025-10-25

はじめに

この記事では AWS SDK for C++ を使い S3 互換ストレージである OCI Object Storage の操作をしている。

基本的には 公式の資料 にある通りです。
SDK のビルドについては こちら を参考にしています。

必要となるソフトウェア

関連するすべてのものは C:\cxx\ を起点として保存している。ダウンロードしたものは C:\cxx\tool\ に展開しパスを通す。
尚、Visual Studio 2022 はインストーラにより導入済である。

  • CMake
    cmake-4.1.2-windows-x86_64.zip

情報収集

OCI ObjectStorage に接続するため、以下の情報が必要になる。

  • リージョン
  • ネームスペース
  • ACCESS キー
  • SECRET キー

リージョンの ID

image.png

image.png

ACCESS&SECRET キー

image.png

image.png

ネームスペース

image.png

プロジェクトの作成

C++ でコンソールアプリを作成する。
C:\cxx\project\01-oci-os\ をプロジェクト・ディレクトリとしている。

image.png

image.png

C++ のバージョンに 17 を指定(任意)。

image.png

aws-sdk-cpp のビルド

上記で作成したプロジェクトのディレクトリに AWS SDK for C++ のソースコードを取得してビルドする。

公式の資料 を参考に以下のコマンドを実行することで C:\cxx\project\01-oci-os\aws-sdk-cpp\dest\ 以下にヘッダとライブラリが作成される。

C:\cxx\project\01-oci-os>set PATH=C:\cxx\tool\cmake-4.1.2-windows-x86_64\bin;%PATH%

C:\cxx\project\01-oci-os>cmake --version
cmake version 4.1.2

CMake suite maintained and supported by Kitware (kitware.com/cmake).

C:\cxx\project\01-oci-os>git clone --recurse-submodules --branch 1.11.675 https://github.com/aws/aws-sdk-cpp.git aws-sdk-cpp\repo
...

C:\cxx\project\01-oci-os>cd aws-sdk-cpp\repo

C:\cxx\project\01-oci-os\aws-sdk-cpp\repo>cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=..\dest\Debug -DBUILD_ONLY="s3" -DCPP_STANDARD=17
...

C:\cxx\project\01-oci-os\aws-sdk-cpp\repo>cmake --build build --config=Debug
...

C:\cxx\project\01-oci-os\aws-sdk-cpp\repo>cmake --install build --config=Debug
...

ここでは C++17 を指定している(任意)。

ビルドした aws-sdk-cpp を参照

上記で生成されたヘッダとライブラリを参照するようにプロジェクトの設定を変更する。

追加のインクルード・ディレクトリ

aws-sdk-cpp の include を指定。
$(SolutionDir)aws-sdk-cpp\dest\$(Configuration)\include

image.png

追加のライブラリ・ディレクトリ

aws-sdk-cpp の bin を指定。
$(SolutionDir)aws-sdk-cpp\dest\$(Configuration)\bin

image.png

実行時 PATH 環境変数

aws-sdk-cpp の bin を指定。
PATH=$(SolutionDir)aws-sdk-cpp\dest\$(Configuration)\bin

image.png

プロジェクトのビルド

OCI_AWS_CPP_SDK_S3_ExamplesAWS SDK Code Examples のソースコードを参考に、以下のファイルを配置した。

事前に準備した ACCESS&SECRET キーは環境変数から取得し、それ以外はハードコードしている。

C:\cxx\project\01-oci-os\01-oci-os.cpp
#pragma comment(lib, "aws-cpp-sdk-core.lib")
#pragma comment(lib, "aws-cpp-sdk-s3.lib")

#include <iostream>
#include <cassert>

void listBuckets(const char* access_key, const char* secret_key);
void listObjects(const char* access_key, const char* secret_key);
void putObject(const char* access_key, const char* secret_key);

int main()
{
	char* access_key = nullptr;
	char* secret_key = nullptr;
	size_t len = 0;

	_dupenv_s(&access_key, &len, "ACCESS_KEY");
	_dupenv_s(&secret_key, &len, "SECRET_KEY");
	assert(access_key && secret_key);

	std::cout << "== listBuckets ==" << std::endl;
	listBuckets(access_key, secret_key);

	std::cout << "== listObjects ==" << std::endl;
	listObjects(access_key, secret_key);

	std::cout << "== putObject ==" << std::endl;
	putObject(access_key, secret_key);

	free(access_key);
	free(secret_key);

	return 0;
}

バケットの一覧を取得。

C:\cxx\project\01-oci-os\listBuckets.cpp
#include <iostream>
#include <cassert>

#define USE_IMPORT_EXPORT

#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/core/auth/AWSCredentialsProviderChain.h>

void listBuckets(const char* access_key, const char* secret_key)
{
	const auto namespc = "**ke***g7**b";
	const auto region = "ap-osaka-1";

	Aws::SDKOptions sdkOptions;
	Aws::InitAPI(sdkOptions);
	Aws::Client::ClientConfiguration cfg;

	cfg.endpointOverride = std::string("https://") + namespc + ".compat.objectstorage." + region + ".oraclecloud.com/";
	cfg.scheme = Aws::Http::Scheme::HTTP;
	cfg.verifySSL = true;
	cfg.region = region;

	Aws::S3::S3Client client(
		Aws::Auth::AWSCredentials(access_key, secret_key), cfg,
		Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, false);

	auto outcome = client.ListBuckets();

	if (outcome.IsSuccess())
	{
		for (auto& bucket : outcome.GetResult().GetBuckets())
		{
			std::cout << bucket.GetName() << std::endl;
		}
	}
	else
	{
		std::cerr << "ERROR: " << outcome.GetError() << std::endl;
	}

	Aws::ShutdownAPI(sdkOptions);
}

images/ に一致するオブジェクトの一覧を取得。

C:\cxx\project\01-oci-os\listObjects.cpp
#include <iostream>
#include <cassert>

#define USE_IMPORT_EXPORT

#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/core/auth/AWSCredentialsProviderChain.h>
#include <aws/s3/model/ListObjectsV2Request.h>

void listObjects(const char* access_key, const char* secret_key)
{
	const auto namespc = "**ke***g7**b";
	const auto region = "ap-osaka-1";

	Aws::SDKOptions sdkOptions;
	Aws::InitAPI(sdkOptions);
	Aws::Client::ClientConfiguration cfg;

	cfg.endpointOverride = std::string("https://") + namespc + ".compat.objectstorage." + region + ".oraclecloud.com/";
	cfg.scheme = Aws::Http::Scheme::HTTP;
	cfg.verifySSL = true;
	cfg.region = region;

	Aws::S3::S3Client client(
		Aws::Auth::AWSCredentials(access_key, secret_key), cfg,
		Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, false);

	Aws::S3::Model::ListObjectsV2Request request;
	request.WithBucket("cxx-project").WithDelimiter("/").WithPrefix("images/");

	auto outcome = client.ListObjectsV2(request);

	if (outcome.IsSuccess())
	{
		for (auto& object : outcome.GetResult().GetContents())
		{
			std::cout << object.GetKey() << std::endl;
		}
	}
	else
	{
		std::cerr << "ERROR: " << outcome.GetError() << std::endl;
	}

	Aws::ShutdownAPI(sdkOptions);
}

ファイルのアップロード。

C:\cxx\project\01-oci-os\putObject.cpp
#include <iostream>
#include <cassert>

#define USE_IMPORT_EXPORT

#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/core/auth/AWSCredentialsProviderChain.h>
#include <aws/s3/model/PutObjectRequest.h>

#include <fstream>
#include <memory>

void putObject(const char* access_key, const char* secret_key)
{
	const auto namespc = "**ke***g7**b";
	const auto region = "ap-osaka-1";

	Aws::SDKOptions sdkOptions;
	Aws::InitAPI(sdkOptions);
	Aws::Client::ClientConfiguration cfg;

	cfg.endpointOverride = std::string("https://") + namespc + ".compat.objectstorage." + region + ".oraclecloud.com/";
	cfg.scheme = Aws::Http::Scheme::HTTP;
	cfg.verifySSL = true;
	cfg.region = region;

	//
	// requestChecksumCalculation の指定は AWS のサンプルと異なる
	// https://github.com/aws/aws-sdk-cpp/issues/3253
	//
	cfg.checksumConfig.requestChecksumCalculation = Aws::Client::RequestChecksumCalculation::WHEN_REQUIRED;

	std::shared_ptr<Aws::IOStream> thisFile = Aws::MakeShared<Aws::FStream>(
		"SampleAllocationTag", __FILE__, std::ios_base::in | std::ios_base::binary);
	assert(*thisFile);

	Aws::S3::S3Client client(
		Aws::Auth::AWSCredentials(access_key, secret_key), cfg,
		Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, false);

	Aws::S3::Model::PutObjectRequest request;
	request.WithBucket("cxx-project").WithKey("putObject.cpp");
	request.SetBody(thisFile);

	auto outcome = client.PutObject(request);

	if (outcome.IsSuccess())
	{
		std::cout << "success" << std::endl;
	}
	else
	{
		std::cerr << "ERROR: " << outcome.GetError() << std::endl;
	}

	Aws::ShutdownAPI(sdkOptions);
}

AWS S3 との違い

バケット、オブジェクトの一覧については参考したソースコードのままでも動作するので、わざわざ記事にする必要もなかった。

しかし、アップロードは 参考にしたコード のままでは以下のエラーが発生した。

ERROR: HTTP response code: 411
Resolved remote host IP address:
Request ID:
Exception name: MissingContentLength
Error message: Unable to parse ExceptionName: MissingContentLength Message: The Content-Length header is required
12 response headers:
access-control-allow-credentials : true
access-control-allow-methods : POST,PUT,GET,HEAD,DELETE,OPTIONS
access-control-allow-origin : *
access-control-expose-headers : access-control-allow-credentials,access-control-allow-methods,access-control-allow-origin,content-length,content-type,date,opc-client-info,opc-request-id,strict-transport-security,x-amz-request-id,x-api-id,x-content-type-options
content-length : 142
content-type : application/xml; charset=utf-8
date : Fri, 24 Oct 2025 21:56:35 GMT
opc-request-id : kix-1:taJ83YFjx5AvrYwvDRVZC8todi...
strict-transport-security : max-age=31536000; includeSubDomains
x-amz-request-id : kix-1:taJ83YFjx5AvrYwvDRVZC8todiNP6R2tccqaV3M...
x-api-id : s3-compatible
x-content-type-options : nosniff

Exception name: MissingContentLength というメッセージをヒントに SetContentLength() を試してみたり、他にも試行錯誤してみたが一向に解決せず、最終的には 公式の issue で案内され、解決方法 を教えてもらった。

おそらく、OCI OS ではリクエストの送信時にチェックサムの扱いが AWS S3 と異なることが原因だと思われる。
(ライブラリのデフォルト値が 2024年末に変更されている)

この結果、以下の一行を追加することで問題が解決した。

cfg.checksumConfig.requestChecksumCalculation = Aws::Client::RequestChecksumCalculation::WHEN_REQUIRED;

実行結果

プロジェクトを実行すると以下の出力が行われる。

== listBuckets ==
bucket-20251025-0453
cxx-project
hello-world
== listObjects ==
images/
images/6419115.png
images/6451979.png
== putObject ==
success

同じバケットに対し oci os コマンドで確認した結果。

(py312) ubuntu@vm1:~$  oci os bucket list | jq -r '.data[].name'
bucket-20251025-0453
cxx-project
hello-world
(py312) ubuntu@vm1:~$ oci os object list --bucket-name=cxx-project | jq -r '.data[].name'
images/
images/6419115.png
images/6451979.png
music/
putObject.cpp
(py312) ubuntu@vm1:~$  oci os object list --bucket-name=cxx-project | jq -r '.data[]|select(.name=="putObject.cpp").size'
1547

プログラムの出力と同じであることが確認できた。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?