//
// Created by yfzx on 2023/3/22.
//
//
// Created by yfzx on 2023/3/14.
//
#include "MINIOGetAndPut.h"
/// 判断待上传的文件是否存在
inline bool file_exists(const string& name)
{
struct stat buffer;
return (stat(name.c_str(), &buffer) == 0);
}
/// 初始化S3连接
S3Client InitS3Client(const Aws::String IPPort, const Aws::String& accessKeyId, const Aws::String& secretKey, std::string securityToken){
// 初始化 S3 Client
Aws::Client::ClientConfiguration cfg;
cfg.endpointOverride = IPPort;
cfg.scheme = Aws::Http::Scheme::HTTP;
cfg.verifySSL = false;
Aws::Auth::AWSCredentials cred(accessKeyId, secretKey, securityToken);
S3Client client(cred, cfg,
Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Always, false);
return client;
}
/// 从MINIO中下载文件或数据
bool doGetObject(const Aws::String &objectKey, const Aws::String &fromBucket, S3Client client, const Aws::String savePath,const Aws::String ®ion)
{
/// 初始化下载请求
Aws::S3::Model::GetObjectRequest object_request;
object_request.SetBucket(fromBucket);
object_request.SetKey(objectKey);
/// 从S3服务器中下载数据
Aws::S3::Model::GetObjectOutcome get_object_outcome = client.GetObject(object_request);
if (get_object_outcome.IsSuccess()) {
/// 保存文件
Aws::OFStream local_file;
local_file.open(savePath, std::ios::out | std::ios::binary);
local_file << get_object_outcome.GetResultWithOwnership().GetBody().rdbuf();
std::cout << "Done!" << std::endl;
return true;
} else {
auto err = get_object_outcome.GetError();
std::cout << "Error: GetObject: " << err.GetExceptionName() << ": " << err.GetMessage() << std::endl;
return false;
}
}
/// 往MINIO上上传文件或数据
bool doPutObject(const Aws::String &objectKey, const Aws::String &fromBucket, S3Client client, const string& file_name, const Aws::String ®ion)
{
// 判断文件是否存在
if (!file_exists(file_name)) {
cout << "ERROR: 找不到这个文件,这个文件不存在"
<< endl;
return false;
}
/// 初始化上传请求
Aws::S3::Model::PutObjectRequest object_request;
object_request.SetBucket(fromBucket);
object_request.SetKey(objectKey);
/// 建立文件输入串流,可为任何串流
const shared_ptr<Aws::IOStream> input_data =
Aws::MakeShared<Aws::FStream>("SampleAllocationTag",
file_name.c_str(),
ios_base::in | ios_base::binary);
object_request.SetBody(input_data);
/// 开始上传至S3
Aws::S3::Model::PutObjectOutcome put_object_outcome = client.PutObject(object_request);
if (!put_object_outcome.IsSuccess()) {
auto error = put_object_outcome.GetError();
cout << "ERROR: " << error.GetExceptionName() << ": "
<< error.GetMessage() << endl;
return false;
}else {
cout << "success" << endl;
return true;
}
}
/// 启动上传程序
bool StartUpLoad(std::string Ips, std::string acccessKey, std::string secretKeyS, std::string bucket_names, std::string object_names, std::string imagename, std::string securityToken){
// 初始化
Aws::SDKOptions options;
options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug;
Aws::InitAPI(options);
/// 设置ip、acccessKey、secretKey
Aws::String IP = Ips;
Aws::String accessKeyId = acccessKey;
Aws::String secretKey = secretKeyS;
S3Client client;
client = InitS3Client(IP, accessKeyId, secretKey, securityToken);
Aws::InitAPI(options);
{
/// 设置上传的目标桶和文件路径
const Aws::String bucket_name = bucket_names;
const Aws::String object_name = object_names;
if (!doPutObject(object_name, bucket_name, client, imagename, " ")) {
std::string errorInfo = object_name + " 上传失败";
writeLog(L_ERROR, errorInfo.c_str());
return false;
}
}
writeLog(L_INFO, "====> 文件上传成功");
return true;
}
/// 启动下载程序
bool StartDownLoad(std::string Ips, std::string acccessKey, std::string secretKeyS, std::string bucket_name, std::string downPath, std::string imagePath, std::string securityToken,
bool &flags){
// 初始化Aws API
Aws::SDKOptions options;
options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug;
Aws::InitAPI(options);
/// 设置ip、acccessKey、secretKey
Aws::String IP = Ips;
Aws::String accessKeyId = acccessKey;
Aws::String secretKey = secretKeyS;
/// 初始化S3服务
S3Client client = InitS3Client(IP, accessKeyId, secretKey, securityToken);
/// 根据get接口的桶名称设置文件所在的桶
Aws::S3::Model::Bucket temps{};
std::string stringK = bucket_name;
temps.SetName(stringK);
/// 查找MINIO相关数据
Aws::S3::Model::ListObjectsRequest objects_request;
objects_request.WithBucket(temps.GetName()); /// 设置桶路径
objects_request.SetPrefix(downPath); /// 设置文件夹路径
auto list_objects_outcome = client.ListObjects(objects_request); /// 判断存储桶及相关连接是否有效
if (flags){
writeLog(L_INFO, "====> 文件下载终止");
return false;
}
if (list_objects_outcome.IsSuccess())
{
/// 获取该目录下的前一千个文件
Aws::Vector<Aws::S3::Model::Object> object_list =
list_objects_outcome.GetResult().GetContents();
if (object_list.size() == 1000){
/// 当下载数量大于一千时 循环下载文件
while(object_list.size() == 1000){
auto finally_object = object_list[0];
for (auto const &s3_object : object_list)
{
if (flags){
writeLog(L_INFO, "====> 文件下载终止");
return false;
}
/// 设置桶名称
const Aws::String bucket_name = stringK;
/// 设置待下载的文件名称
const Aws::String object_name = s3_object.GetKey();
/// 设置保存文件路径及文件名称
std::string NewPath;
size_t indexNew = object_name.find_last_of('/');
NewPath = object_name.substr(indexNew + 1, object_name.length());
const Aws::String SavePath = imagePath + NewPath;
size_t indexK = downPath.find_last_of('/');
std::string newPathEs = downPath.substr(0, indexK);
std::string strK;
strK = imagePath + "/" + NewPath;
const Aws::String SavePaths = strK;
//筛选数据
std::string fileName;
size_t index = object_name.find_last_of('.');
fileName = object_name.substr(index + 1, object_name.length());
if (fileName == "JPG" || fileName == "jpeg" || fileName == "JPEG" || fileName == "jpg"){
/// 启动下载
if (!doGetObject(object_name, bucket_name, client,SavePaths,"")) {
std::string errorInfo = object_name + " 下载失败";
writeLog(L_ERROR, errorInfo.c_str());
continue;
}
}
}
finally_object = object_list[999];
/// 重新配置相关路径
objects_request.WithBucket(temps.GetName()); /// 设置桶路径
objects_request.SetPrefix(finally_object.GetKey()); /// 设置新文件夹路径
MINIO服务器基于AWS S3 SDK 文件上传及下载(C++实现类)
需积分: 0 94 浏览量
更新于2023-11-14
1
收藏 5KB ZIP 举报
MINIO服务器是一款开源的对象存储系统,它模仿了亚马逊的S3云存储服务。在这个场景中,我们将探讨如何使用AWS S3 SDK(Software Development Kit)在C++中实现对MINIO服务器上的文件进行上传和下载。AWS S3 SDK为开发者提供了方便的API接口,可以轻松地在应用程序中集成S3服务。
我们需要理解C++中的对象模型和AWS SDK的使用。AWS SDK for C++提供了一组库,用于与Amazon Web Services进行交互。为了与MINIO服务器通信,我们需要包含相关的头文件并链接SDK库。
1. **初始化SDK**: 在C++程序开始时,我们需要初始化AWS SDK。这通常涉及设置AWS区域、身份验证凭据(Access Key ID和Secret Access Key)以及配置HTTP客户端。
```cpp
#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
Aws::SDKOptions options;
Aws::InitAPI(options);
// 设置区域,例如:Aws::Region::US_EAST_1
Aws::Client::ClientConfiguration clientConfig;
clientConfig.region = Aws::Region::US_EAST_1;
// 创建S3客户端
std::unique_ptr<Aws::S3::S3Client> s3Client = std::make_unique<Aws::S3::S3Client>(clientConfig);
```
2. **文件上传**: 使用S3 SDK的`PutObject`函数将本地文件上传到MINIO服务器。这个操作可能需要分片上传,特别是处理大文件时。分片上传可以提高上传效率和容错性。
```cpp
#include <aws/s3/model/PutObjectRequest.h>
#include <fstream>
// 上传文件
void uploadFile(const std::string& bucketName, const std::string& key, const std::string& filePath) {
Aws::S3::Model::PutObjectRequest putObjectRequest;
putObjectRequest.WithBucket(bucketName).WithKey(key);
std::ifstream file(filePath, std::ios::binary);
putObjectRequest.SetBody(file);
auto outcome = s3Client->PutObject(putObjectRequest);
if (!outcome.IsSuccess()) {
std::cerr << "Upload failed: " << outcome.GetError().GetMessage() << std::endl;
}
}
```
3. **文件下载**: 下载文件则使用`GetObject`函数。同样,如果文件较大,SDK会自动处理分片下载。
```cpp
#include <aws/s3/model/GetObjectRequest.h>
#include <ofstream>
// 下载文件
void downloadFile(const std::string& bucketName, const std::string& key, const std::string& outputPath) {
Aws::S3::Model::GetObjectRequest getObjectRequest;
getObjectRequest.WithBucket(bucketName).WithKey(key);
auto outcome = s3Client->GetObject(getObjectRequest);
if (outcome.IsSuccess()) {
std::ofstream outputFile(outputPath, std::ios::binary);
outputFile << outcome.GetResult().GetBody().rdbuf();
outputFile.close();
} else {
std::cerr << "Download failed: " << outcome.GetError().GetMessage() << std::endl;
}
}
```
4. **分片上传**: 对于大文件,AWS S3 SDK支持Multipart Upload,即将文件分成多个部分并独立上传,然后合并这些部分。这在上传过程中提供了更好的错误恢复能力。
```cpp
#include <aws/s3/model/CreateMultipartUploadRequest.h>
#include <aws/s3/model/UploadPartRequest.h>
#include <aws/s3/model/CompleteMultipartUploadRequest.h>
// 分片上传
void multipartUpload(const std::string& bucketName, const std::string& key, const std::string& filePath) {
// 创建Multipart上传
auto createOutcome = s3Client->CreateMultipartUpload(Aws::S3::Model::CreateMultipartUploadRequest().WithBucket(bucketName).WithKey(key));
if (!createOutcome.IsSuccess()) {
std::cerr << "Create Multipart Upload failed: " << createOutcome.GetError().GetMessage() << std::endl;
return;
}
auto uploadId = createOutcome.GetResult().GetUploadId();
// 分片并上传
std::ifstream file(filePath, std::ios::binary);
long fileSize = file.seekg(0, std::ios::end).tellg();
file.seekg(0, std::ios::beg);
const int partSize = 5 * 1024 * 1024; // 每个部分5MB
for (int i = 0; i < fileSize / partSize; ++i) {
Aws::S3::Model::UploadPartRequest uploadRequest;
uploadRequest.WithBucket(bucketName).WithKey(key).WithUploadId(uploadId);
uploadRequest.SetPartNumber(i + 1);
uploadRequest.SetBody(std::make_shared<std::istream>(file));
auto uploadOutcome = s3Client->UploadPart(uploadRequest);
if (!uploadOutcome.IsSuccess()) {
std::cerr << "Upload Part " << i + 1 << " failed: " << uploadOutcome.GetError().GetMessage() << std::endl;
return;
}
}
// 完成Multipart上传
std::vector<Aws::S3::Model::CompletedPart> completedParts;
for (int i = 0; i < fileSize / partSize; ++i) {
completedParts.push_back(Aws::S3::Model::CompletedPart().WithPartNumber(i + 1).WithETag(uploadOutcome.GetResult().GetETag()));
}
Aws::S3::Model::CompleteMultipartUploadRequest completeRequest;
completeRequest.WithBucket(bucketName).WithKey(key).WithUploadId(uploadId).WithCompletedParts(completedParts);
auto completeOutcome = s3Client->CompleteMultipartUpload(completeRequest);
if (!completeOutcome.IsSuccess()) {
std::cerr << "Complete Multipart Upload failed: " << completeOutcome.GetError().GetMessage() << std::endl;
}
}
```
请注意,实际应用中需要处理各种错误情况,并确保在完成上传或下载后正确清理资源。在上述代码示例中,我们仅展示了基本的上传和下载流程,实际项目中可能需要进行更复杂的错误处理和状态管理。
总结,MINIO服务器的文件上传和下载可通过AWS S3 SDK在C++中实现,利用SDK提供的功能如`PutObject`、`GetObject`、`CreateMultipartUpload`等,结合适当的错误处理和流操作,可以创建高效且可靠的文件存取程序。同时,对于大文件,分片上传能提供更好的性能和可靠性。