「Qtの応用 - AWS S3」の版間の差分

提供: MochiuWiki : SUSE, EC, PCB

 
(同じ利用者による、間の4版が非表示)
1行目: 1行目:
== 概要 ==
== 概要 ==
 
Amazon S3 (Simple Storage Service) は、AWSが提供するオブジェクトストレージサービスである。<br>
インターネット経由でデータの保存と取得が可能であり、スケーラビリティ、可用性、セキュリティ、パフォーマンスに優れている。<br>
<br>
S3では、データは「オブジェクト」として保存され、各オブジェクトは「バケット」と呼ばれるコンテナ内に格納される。<br>
オブジェクトは、ファイル本体とそのメタデータで構成され、一意の「キー」 (ファイル名やパス) により識別される。<br>
バケット名はグローバルに一意である必要がある。<br>
<br>
主な特徴として、事実上無制限のストレージ容量、高い耐久性 (99.999999999[%])、複数のストレージクラスによるコスト最適化、バージョニング機能、アクセス制御、暗号化等がある。<br>
静的Webサイトのホスティング、バックアップとアーカイブ、ビッグデータ分析、アプリケーションデータの保存等、幅広い用途で利用されている。<br>
<br>
S3へのアクセスは、AWSマネジメントコンソール、AWS CLI、AWS SDKを通じて行うことができ、RESTful APIを介してプログラムから操作することが可能である。<br>
<br><br>
<br><br>


8行目: 18行目:


== S3へのアップロード ==
== S3へのアップロード ==
 
ローカルファイルをS3バケットにストリーム経由でアップロードするフローを以下に示す。<br>
# ClientConfigurationの作成
#: AWS SDKのクライアント設定オブジェクトを生成する。
# リージョンの設定
#: 指定されたAWSリージョンを設定する。
# S3クライアントの生成
<br>
==== S3クライアントの初期化 ====
指定されたリージョンでS3クライアントを初期化する。<br>
<br>
<syntaxhighlight lang="c++">
QString region = "<リージョン名>"
Aws::Client::ClientConfiguration clientConfig;
clientConfig.region = region.toStdString();
auto s3Client = std::make_unique<Aws::S3::S3Client>(clientConfig);
</syntaxhighlight>
<br>
==== アップロードフロー ====
* bucketName
*: アップロード先のS3バケット名
* objectKey
*: S3上でのオブジェクトキー (パス)
* filePath
*: アップロードするローカルファイルのパス
<br>
<syntaxhighlight lang="c++">
// 1. ファイル存在チェック
QFileInfo fileInfo(filePath);
if (!fileInfo.exists()) {
  return false;
}
// 2. PutObjectRequestの設定
Aws::S3::Model::PutObjectRequest request;
request.SetBucket(bucketName.toStdString());
request.SetKey(objectKey.toStdString());
// 3. ファイルストリームの作成
// Aws::MakeSharedは、AWS SDK専用のスマートポインタ
auto inputData = Aws::MakeShared<Aws::FStream>(
    "PutObjectInputStream",
    filePath.toStdString().c_str(),
    std::ios_base::in | std::ios_base::binary  // std::ios_base::binary でバイナリファイルにも対応
);
// 4. リクエストにデータを設定
request.SetBody(inputData);
request.SetContentLength(fileInfo.size());  // ファイルサイズを明示的に設定 (Content-Length)
// 5. アップロード実行
auto outcome = s3Client->PutObject(request);
if (outcome.IsSuccess()) {  // outcome.IsSuccessメソッドは、成功 / 失敗を判定することができる
    std::cout << "✓ アップロード成功" << std::endl;
    return true;
}
else {
    std::cerr << "✗ アップロード失敗: " << outcome.GetError().GetMessage() << std::endl;
    return false;
}
</syntaxhighlight>
<br><br>
<br><br>


== S3へのダウンロード ==
== S3へのダウンロード ==
S3バケットからファイルをストリーム経由でダウンロードするフローを以下に示す。<br>
# ClientConfigurationの作成
#: AWS SDKのクライアント設定オブジェクトを生成する。
# リージョンの設定
#: 指定されたAWSリージョンを設定する。
# S3クライアントの生成
<br>
==== S3クライアントの初期化 ====
指定されたリージョンでS3クライアントを初期化する。<br>
<br>
<syntaxhighlight lang="c++">
QString region = "<リージョン名>"
Aws::Client::ClientConfiguration clientConfig;
clientConfig.region = region.toStdString();
auto s3Client = std::make_unique<Aws::S3::S3Client>(clientConfig);
</syntaxhighlight>
<br>
==== アップロードフロー ====
* bucketName
*: ダウンロード元のS3バケット名
* objectKey
*: S3上でのオブジェクトキー (パス)
* filePath
*: ダウンロード先のローカルファイルパス
<br>
<syntaxhighlight lang="c++">
// 1. GetObjectRequestの設定
Aws::S3::Model::GetObjectRequest request;
request.SetBucket(bucketName.toStdString());
request.SetKey(objectKey.toStdString());


// 2. ダウンロード実行
auto outcome = m_s3Client->GetObject(request);
// 3. 成功時の処理
if (outcome.IsSuccess()) {
  // ストリームの取得
  // GetResultWithOwnership : 結果オブジェクトの所有権を取得
  auto& retrieved_file = outcome.GetResultWithOwnership().GetBody();  // ダウンロードしたデータのストリームを取得
  // ローカルファイルへの書き込み
  std::ofstream output_file(filePath.toStdString(), std::ios::binary);  // ファイル書き込み時もバイナリモードを使用
  output_file << retrieved_file.rdbuf();  // ストリームバッファを直接ファイルに書き込み
  output_file.close();
}
</syntaxhighlight>
<br><br>
<br><br>


19行目: 135行目:
全ての設定 (リージョン、バケット名、オブジェクトキー) を任意の設定ファイルから読み込んでいる。<br>
全ての設定 (リージョン、バケット名、オブジェクトキー) を任意の設定ファイルから読み込んでいる。<br>
<br>
<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="ini">
  # config.iniファイル
  # config.iniファイル
   
   

2025年11月21日 (金) 15:20時点における最新版

概要

Amazon S3 (Simple Storage Service) は、AWSが提供するオブジェクトストレージサービスである。
インターネット経由でデータの保存と取得が可能であり、スケーラビリティ、可用性、セキュリティ、パフォーマンスに優れている。

S3では、データは「オブジェクト」として保存され、各オブジェクトは「バケット」と呼ばれるコンテナ内に格納される。
オブジェクトは、ファイル本体とそのメタデータで構成され、一意の「キー」 (ファイル名やパス) により識別される。
バケット名はグローバルに一意である必要がある。

主な特徴として、事実上無制限のストレージ容量、高い耐久性 (99.999999999[%])、複数のストレージクラスによるコスト最適化、バージョニング機能、アクセス制御、暗号化等がある。
静的Webサイトのホスティング、バックアップとアーカイブ、ビッグデータ分析、アプリケーションデータの保存等、幅広い用途で利用されている。

S3へのアクセスは、AWSマネジメントコンソール、AWS CLI、AWS SDKを通じて行うことができ、RESTful APIを介してプログラムから操作することが可能である。


AWS SDK for C++のインストール

Qtの応用_-_AWS#AWS_SDK_for_C++のインストールのページを参照すること。


S3へのアップロード

ローカルファイルをS3バケットにストリーム経由でアップロードするフローを以下に示す。

  1. ClientConfigurationの作成
    AWS SDKのクライアント設定オブジェクトを生成する。
  2. リージョンの設定
    指定されたAWSリージョンを設定する。
  3. S3クライアントの生成


S3クライアントの初期化

指定されたリージョンでS3クライアントを初期化する。

 QString region = "<リージョン名>"
 
 Aws::Client::ClientConfiguration clientConfig;
 clientConfig.region = region.toStdString();
 auto s3Client = std::make_unique<Aws::S3::S3Client>(clientConfig);


アップロードフロー

  • bucketName
    アップロード先のS3バケット名
  • objectKey
    S3上でのオブジェクトキー (パス)
  • filePath
    アップロードするローカルファイルのパス


 // 1. ファイル存在チェック
 QFileInfo fileInfo(filePath);
 if (!fileInfo.exists()) {
   return false;
 }
 
 // 2. PutObjectRequestの設定
 Aws::S3::Model::PutObjectRequest request;
 request.SetBucket(bucketName.toStdString());
 request.SetKey(objectKey.toStdString());
 
 // 3. ファイルストリームの作成
 // Aws::MakeSharedは、AWS SDK専用のスマートポインタ
 auto inputData = Aws::MakeShared<Aws::FStream>(
    "PutObjectInputStream", 
    filePath.toStdString().c_str(), 
    std::ios_base::in | std::ios_base::binary  // std::ios_base::binary でバイナリファイルにも対応
 );
 
 // 4. リクエストにデータを設定
 request.SetBody(inputData);
 request.SetContentLength(fileInfo.size());  // ファイルサイズを明示的に設定 (Content-Length)
 
 // 5. アップロード実行
 auto outcome = s3Client->PutObject(request);
 if (outcome.IsSuccess()) {  // outcome.IsSuccessメソッドは、成功 / 失敗を判定することができる
    std::cout << "✓ アップロード成功" << std::endl;
    return true;
 }
 else {
    std::cerr << "✗ アップロード失敗: " << outcome.GetError().GetMessage() << std::endl;
    return false;
 }



S3へのダウンロード

S3バケットからファイルをストリーム経由でダウンロードするフローを以下に示す。

  1. ClientConfigurationの作成
    AWS SDKのクライアント設定オブジェクトを生成する。
  2. リージョンの設定
    指定されたAWSリージョンを設定する。
  3. S3クライアントの生成


S3クライアントの初期化

指定されたリージョンでS3クライアントを初期化する。

 QString region = "<リージョン名>"

 Aws::Client::ClientConfiguration clientConfig;
 clientConfig.region = region.toStdString();
 auto s3Client = std::make_unique<Aws::S3::S3Client>(clientConfig);


アップロードフロー

  • bucketName
    ダウンロード元のS3バケット名
  • objectKey
    S3上でのオブジェクトキー (パス)
  • filePath
    ダウンロード先のローカルファイルパス


 // 1. GetObjectRequestの設定
 Aws::S3::Model::GetObjectRequest request;
 request.SetBucket(bucketName.toStdString());
 request.SetKey(objectKey.toStdString());

 // 2. ダウンロード実行
 auto outcome = m_s3Client->GetObject(request);

 // 3. 成功時の処理
 if (outcome.IsSuccess()) {
   // ストリームの取得
   // GetResultWithOwnership : 結果オブジェクトの所有権を取得
   auto& retrieved_file = outcome.GetResultWithOwnership().GetBody();  // ダウンロードしたデータのストリームを取得

   // ローカルファイルへの書き込み
   std::ofstream output_file(filePath.toStdString(), std::ios::binary);  // ファイル書き込み時もバイナリモードを使用
   output_file << retrieved_file.rdbuf();  // ストリームバッファを直接ファイルに書き込み
   output_file.close();
 }



サンプルコード

以下の例では、AWS S3へのファイルアップロードとダウンロードを行っている。
全ての設定 (リージョン、バケット名、オブジェクトキー) を任意の設定ファイルから読み込んでいる。

 # config.iniファイル
 
 [AWS]
 # AWSリージョン (必須)
 region=us-east-1
 
 [S3]
 # S3バケット名 (必須)
 bucket=my-bucket-name
 
 [Upload]
 # アップロード時のS3オブジェクトキー
 object_key=uploads/myfile.txt
 
 # アップロードするローカルファイルのパス
 local_file=/path/to/local/file.txt
 
 [Download]
 # ダウンロードするS3オブジェクトキー
 object_key=downloads/myfile.txt
 
 # ダウンロード先のローカルファイルパス
 local_file=/path/to/save/file.txt


 # CMakeLists.txtファイル
 
 cmake_minimum_required(VERSION 3.16)
 project(<プロジェクト名> VERSION 1.0 LANGUAGES CXX)
 
 set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
 # Qt設定
 set(CMAKE_AUTOMOC ON)
 set(CMAKE_AUTORCC ON)
 set(CMAKE_AUTOUIC ON)
 
 # Qtの検索
 find_package(Qt6 COMPONENTS Core QUIET)
 if (NOT Qt6_FOUND)
    find_package(Qt5 5.15 REQUIRED COMPONENTS Core)
 endif()
 
 # AWS SDK for C++の検索
 find_package(AWSSDK REQUIRED COMPONENTS s3)
 
 # 実行ファイル
 add_executable(<プロジェクト名>
    main.cpp
 )
 
 # Qt6とQt5の両方に対応
 if (Qt6_FOUND)
    target_link_libraries(<プロジェクト名>
       Qt6::Core
       ${AWSSDK_LINK_LIBRARIES}
    )
 else()
    target_link_libraries(<プロジェクト名>
       Qt5::Core
       ${AWSSDK_LINK_LIBRARIES}
    )
 endif()
 
 # インストール
 install(TARGETS <プロジェクト名>
    RUNTIME DESTINATION bin
 )


 #include <QCoreApplication>
 #include <QCommandLineParser>
 #include <QSettings>
 #include <QFile>
 #include <QFileInfo>
 #include <QDebug>
 #include <fstream>
 #include <iostream>
 #include <aws/core/Aws.h>
 #include <aws/s3/S3Client.h>
 #include <aws/s3/model/PutObjectRequest.h>
 #include <aws/s3/model/GetObjectRequest.h>
 
 // 設定情報を保持する構造体
 struct S3Config {
    QString region;
    QString bucket;
    QString uploadObjectKey;
    QString uploadLocalFile;
    QString downloadObjectKey;
    QString downloadLocalFile;
 };
 
 // 設定ファイルを読み込む関数
 bool loadConfig(const QString& configPath, S3Config& config)
 {
    QFileInfo fileInfo(configPath);
    if (!fileInfo.exists()) {
       std::cerr << "エラー: 設定ファイルが見つかりません: " << configPath.toStdString() << std::endl;
       return false;
    }
 
    QSettings settings(configPath, QSettings::IniFormat);
    settings.setIniCodec("UTF-8");
 
    // AWS設定
    settings.beginGroup("AWS");
    config.region = settings.value("region").toString();
    settings.endGroup();
 
    // S3設定
    settings.beginGroup("S3");
    config.bucket = settings.value("bucket").toString();
    settings.endGroup();
 
    // アップロード設定
    settings.beginGroup("Upload");
    config.uploadObjectKey = settings.value("object_key").toString();
    config.uploadLocalFile = settings.value("local_file").toString();
    settings.endGroup();
 
    // ダウンロード設定
    settings.beginGroup("Download");
    config.downloadObjectKey = settings.value("object_key").toString();
    config.downloadLocalFile = settings.value("local_file").toString();
    settings.endGroup();
 
    // 必須項目のチェック
    if (config.region.isEmpty()) {
       std::cerr << "エラー: [AWS] region が設定されていません" << std::endl;
       return false;
    }
    if (config.bucket.isEmpty()) {
       std::cerr << "エラー: [S3] bucket が設定されていません" << std::endl;
       return false;
    }
 
    std::cout << "設定ファイル読み込み完了: " << configPath.toStdString() << std::endl;
    std::cout << "  リージョン: " << config.region.toStdString() << std::endl;
    std::cout << "  バケット名: " << config.bucket.toStdString() << std::endl;
 
    return true;
 }
 
 class S3Manager {
 private:
    std::unique_ptr<Aws::S3::S3Client> m_s3Client;
 
 public:
    S3Manager(const QString& region)
    {
       Aws::Client::ClientConfiguration clientConfig;
       clientConfig.region = region.toStdString();
       m_s3Client = std::make_unique<Aws::S3::S3Client>(clientConfig);
 
       std::cout << "S3クライアント初期化完了 (リージョン: " << region.toStdString() << ")" << std::endl;
    }
 
    bool uploadFile(const QString& bucketName, const QString& objectKey, const QString& filePath)
    {
       std::cout << "\n=== アップロード開始 ===" << std::endl;
       std::cout << "  ローカルファイル: " << filePath.toStdString() << std::endl;
       std::cout << "  S3パス: s3://" << bucketName.toStdString()  << "/" << objectKey.toStdString() << std::endl;
 
       // ファイルの存在チェック
       QFileInfo fileInfo(filePath);
       if (!fileInfo.exists()) {
          std::cerr << "エラー: ファイルが見つかりません: " << filePath.toStdString() << std::endl;
          return false;
       }
 
       Aws::S3::Model::PutObjectRequest request;
       request.SetBucket(bucketName.toStdString());
       request.SetKey(objectKey.toStdString());
 
       // ファイルをストリームとして読み込む
       auto inputData = Aws::MakeShared<Aws::FStream>("PutObjectInputStream", filePath.toStdString().c_str(), std::ios_base::in | std::ios_base::binary);
 
       if (!inputData->is_open()) {
          std::cerr << "エラー: ファイルを開けません: " << filePath.toStdString() << std::endl;
          return false;
       }
 
       request.SetBody(inputData);
       request.SetContentLength(fileInfo.size());
 
       auto outcome = m_s3Client->PutObject(request);
 
       if (outcome.IsSuccess()) {
          std::cout << "✓ アップロード成功!" << std::endl;
          return true;
       }
       else {
          std::cerr << "✗ アップロード失敗: " << outcome.GetError().GetMessage() << std::endl;
          return false;
       }
    }
 
    bool downloadFile(const QString& bucketName, const QString& objectKey, const QString& filePath)
    {
       std::cout << "\n=== ダウンロード開始 ===" << std::endl;
       std::cout << "  S3パス: s3://" << bucketName.toStdString() << "/" << objectKey.toStdString() << std::endl;
       std::cout << "  保存先: " << filePath.toStdString() << std::endl;
 
       Aws::S3::Model::GetObjectRequest request;
       request.SetBucket(bucketName.toStdString());
       request.SetKey(objectKey.toStdString());
 
       auto outcome = m_s3Client->GetObject(request);
 
       if (outcome.IsSuccess()) {
          auto& retrieved_file = outcome.GetResultWithOwnership().GetBody();
 
          std::ofstream output_file(filePath.toStdString(), std::ios::binary);
          if (!output_file.is_open()) {
             std::cerr << "エラー: 保存先ファイルを開けません: " << filePath.toStdString() << std::endl;
             return false;
          }
 
          output_file << retrieved_file.rdbuf();
          output_file.close();
 
          // ファイルサイズを表示
          QFileInfo fileInfo(filePath);
          std::cout << "✓ ダウンロード成功! (サイズ: " << fileInfo.size() << " bytes)" << std::endl;
          return true;
       }
       else {
          std::cerr << "✗ ダウンロード失敗: " << outcome.GetError().GetMessage() << std::endl;
          return false;
       }
    }
 };
 
 int main(int argc, char *argv[])
 {
    QCoreApplication app(argc, argv);
    QCoreApplication::setApplicationName("AWS S3 Manager");
    QCoreApplication::setApplicationVersion("1.0");
 
    // コマンドライン引数のパーサーを設定
    QCommandLineParser parser;
    parser.setApplicationDescription("AWS S3ファイルアップロード・ダウンロードツール (設定ファイルベース)");
    parser.addHelpOption();
    parser.addVersionOption();
 
    // オプション定義
    QCommandLineOption uploadOption(QStringList() << "u" << "upload", "ファイルをアップロード");
    parser.addOption(uploadOption);
 
    QCommandLineOption downloadOption(QStringList() << "d" << "download", "ファイルをダウンロード");
    parser.addOption(downloadOption);
 
    QCommandLineOption configOption(QStringList() << "c" << "config",  "設定ファイルのパス (デフォルト: config.ini)", "config", "config.ini");
    parser.addOption(configOption);
 
    parser.process(app);
 
    // AWS SDKの初期化
    Aws::SDKOptions options;
    Aws::InitAPI(options);
 
    int result = 0;
 
    {
       // 設定ファイルのパスを取得
       QString configPath = parser.value(configOption);
 
       // 設定を読み込む
       S3Config config;
       if (!loadConfig(configPath, config)) {
          std::cerr << "\n設定ファイルの例:" << std::endl;
          std::cerr << "  [AWS]" << std::endl;
          std::cerr << "  region=ap-northeast-1" << std::endl;
          std::cerr << "  " << std::endl;
          std::cerr << "  [S3]" << std::endl;
          std::cerr << "  bucket=my-bucket-name" << std::endl;
          std::cerr << "  " << std::endl;
          std::cerr << "  [Upload]" << std::endl;
          std::cerr << "  object_key=folder/myfile.txt" << std::endl;
          std::cerr << "  local_file=/path/to/local/file.txt" << std::endl;
          std::cerr << "  " << std::endl;
          std::cerr << "  [Download]" << std::endl;
          std::cerr << "  object_key=folder/myfile.txt" << std::endl;
          std::cerr << "  local_file=/path/to/save/file.txt" << std::endl;
          Aws::ShutdownAPI(options);
          return 1;
       }
 
       // S3マネージャーを初期化
       S3Manager s3Manager(config.region);
 
       if (parser.isSet(uploadOption)) {
          // アップロード
          if (config.uploadObjectKey.isEmpty() || config.uploadLocalFile.isEmpty()) {
             std::cerr << "エラー: [Upload] セクションに object_key と local_file が必要です" << std::endl;
             result = 1;
          }
          else {
             if (!s3Manager.uploadFile(config.bucket, config.uploadObjectKey, config.uploadLocalFile)) {
                result = 1;
             }
          }
       }
       else if (parser.isSet(downloadOption)) {
          // ダウンロード
          if (config.downloadObjectKey.isEmpty() || config.downloadLocalFile.isEmpty()) {
             std::cerr << "エラー: [Download] セクションに object_key と local_file が必要です" << std::endl;
             result = 1;
          }
          else {
             if (!s3Manager.downloadFile(config.bucket, config.downloadObjectKey, config.downloadLocalFile)) {
                result = 1;
             }
          }
       }
       else {
          std::cerr << "エラー: --upload または --download を指定してください" << std::endl;
          parser.showHelp(1);
       }
    }
 
    // AWS SDKのクリーンアップ
    Aws::ShutdownAPI(options);
 
    return result;
 }