Qtの応用 - AWS S3
提供: MochiuWiki : SUSE, EC, PCB
概要
AWS SDK for C++のインストール
Qtの応用_-_AWS#AWS_SDK_for_C++のインストールのページを参照すること。
S3へのアップロード
ローカルファイルをS3バケットにストリーム経由でアップロードするフローを以下に示す。
- ClientConfigurationの作成
- AWS SDKのクライアント設定オブジェクトを生成する。
- リージョンの設定
- 指定されたAWSリージョンを設定する。
- 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);
また、outcome.IsSuccessメソッドを使用して、成功 / 失敗を判定することができる。
S3へのダウンロード
サンプルコード
以下の例では、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;
}