项目中用到了阿里云OSS对象存储来保存数据,由于以前没用过这个库,就下载了C++版的sdk源码重新编译了一次,并使用Qt调用;不得不说这可能是我编译源码最轻松的一次。
目录标题
- 简述
- OSS图形化管理工具
- 编译源码
- Qt 添加引用
- 常用 Endpoint
- 使用方法
- 上传示例:
- 直接读取OSS下载缓存,不写入文件:
- 进度下载:
- 测试时遇到的两个问题
- 添加<windows.h>头文件时无法识别外部链接GetObjectW
- 在添加进度条下载功能时,静态方法发送信号
简述
阿里云对象存储(Object Storage Service,简称OSS),是阿里云对外提供的海量、安全、低成本、高可靠的云存储服务。用户可以通过调用API,在任何应用、任何时间、任何地点上传和下载数据,也可以通过用户Web控制台对数据进行简单的管理。OSS适合存放任意文件类型,适合各种网站、开发企业及开发者使用。
适用于阿里云OSS的 C++ SDK提供了一组现代化的 C++(C++ 11)接口,让您不用复杂编程即可访问阿里云OSS服务。
如果您在使用SDK的过程中遇到任何问题,欢迎前往阿里云SDK问答社区提问,提问前请阅读提问引导:
阿里云OSS C++工具套件
直接下载C++版SDK
通过GitHub下载
OSS图形化管理工具
ossbrowser是阿里云官方提供的OSS图形化管理工具,提供类似Windows资源管理器的功能
OSS图形化管理工具 直接下载【oss-browser-win32-x64】
阿里云产品文档-安装并登录ossbrowser
编译源码
OSS的SDK只有少数的几个配置项,直接默认生成就行,如果需要配置,可以查看 CMAKE 选项
生成以下文件:
使用vs打开alibabacloud-oss-cpp-sdk.sln重新生成cpp-sdk:
Qt 添加引用
Qt 调用需要把 SDK中的文件夹放在项目目录下,并添加引用
# 动态库链接
# /OSS/include 路径中oss为新建文件夹
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/OSS/lib/Release/ -lalibabacloud-oss-cpp-sdk
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/OSS/lib/Debug/ -lalibabacloud-oss-cpp-sdk
INCLUDEPATH += $$PWD/OSS/include
DEPENDPATH += $$PWD/OSS/include
同时需要把third_party中的dll添加进去
//注意64位与32位应选择不同文件夹
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/OSS/other/x64/ -llibeay32
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/OSS/other/x64/ -llibeay32
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/OSS/other/x64/ -lssleay32
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/OSS/other/x64/ -lssleay32
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/OSS/other/x64/ -llibcurl
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/OSS/other/x64/ -llibcurl
常用 Endpoint
在调用oss库时,看一遍说明文档是必要的,就比如Endpoint 这个参数费半天的劲猜对,才发现有详细说明C++初始化;
#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;
///地区
QMap<QString,QString> Mapdata;
Mapdata.insert("华东1(杭州)","oss-cn-hangzhou.aliyuncs.com");
Mapdata.insert("华东2(上海)","oss-cn-shanghai.aliyuncs.com");
Mapdata.insert("华东5(南京-本地地域)","oss-cn-nanjing.aliyuncs.com");
Mapdata.insert("华北1(青岛)","oss-cn-qingdao.aliyuncs.com");
Mapdata.insert("华北2(北京)","oss-cn-beijing.aliyuncs.com");
Mapdata.insert("华北3(张家口)","oss-cn-zhangjiakou.aliyuncs.com");
Mapdata.insert("华北5(呼和浩特)","oss-cn-huhehaote.aliyuncs.com");
Mapdata.insert("华北6(乌兰察布)","oss-cn-wulanchabu.aliyuncs.com");
Mapdata.insert("华南1(深圳)","oss-cn-shenzhen.aliyuncs.com");
Mapdata.insert("华南2(河源)","oss-cn-heyuan.aliyuncs.com");
Mapdata.insert("华南3(广州)","oss-cn-guangzhou.aliyuncs.com");
Mapdata.insert("西南1(成都)","oss-cn-chengdu.aliyuncs.com");
int main(void)
{
/* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
std::string Endpoint = "yourEndpoint";
/* 从STS服务获取的临时访问密钥(AccessKey ID和AccessKey Secret)。*/
std::string AccessKeyId = "yourAccessKeyId";
std::string AccessKeySecret = "yourAccessKeySecret";
/* 从STS服务获取的安全令牌(SecurityToken)。*/
std::string SecurityToken = "yourSecurityToken";
/* 初始化网络等资源。*/
InitializeSdk();
ClientConfiguration conf;
OssClient client(Endpoint, AccessKeyId, AccessKeySecret, SecurityToken, conf);
/* 释放网络等资源。*/
ShutdownSdk();
return 0;
}
使用方法
OSS C++ SDK提供丰富的示例代码
在OSS C++ SDk中ObjectSample.h文件提供了大多数方法的调用示例,
如:
上传示例:
//PutObjectFromFile()
qDebug()<<"[__FILE__] "<<__FILE__;
QFileInfo info("E:\\LOCAL_FTP\\archival-information.xml");
qDebug()<<info.exists();
std::shared_ptr<std::iostream> content = std::make_shared<std::fstream>(info.absoluteFilePath().toStdString(), std::ios::in | std::ios::binary);
PutObjectRequest request(bucket_, info.fileName().toStdString(), content);
auto outcome = client->PutObject(request);
if (outcome.isSuccess()) {
std::cout << __FUNCTION__ << " success, ETag:" << outcome.result().ETag() << std::endl;
}
else {
PrintError(__FUNCTION__, outcome.error());
}
直接读取OSS下载缓存,不写入文件:
// 初始化SDK
InitializeSdk();
QString Data_XML="";
ClientConfiguration conf;
OssClient* client = new OssClient(OSS_Config::OSS_Endpoint, OSS_Config::OSS_AccessKeyId, OSS_Config::OSS_AccessKeySecret, conf);
{
std::shared_ptr<std::stringstream> content = std::make_shared<std::stringstream>();
GetObjectRequest request(OSS_Config::OSS_Buckets, OSS_Path.toStdString());
request.setResponseStreamFactory([=](){
return content;
});
auto outcome = client->GetObject(request);
if (outcome.isSuccess()) {
Data_XML=QString::fromStdString(content->str());
}
else {
OSS_Config::instance().PrintError(__FUNCTION__, outcome.error());
}
}
// 关闭SDK
ShutdownSdk();
进度下载:
当通过线程进行下载时注意 通过ProgressCallback方法获取下载的进度显示,需要注意的是ProgressCallback方法必须为静态方法,
static void ProgressCallback(size_t increment, int64_t transfered, int64_t total, void* userData)
{
std::cout << "ProgressCallback[" << userData << "] => " <<
increment <<" ," << transfered << "," << total << std::endl;
}
{
DownloadObjectRequest request(bucket_, "xxx.pdf", Config::FileDownloadTo, "", 100*1024, 0 );
TransferProgress progressCallback = { ProgressCallback , this };
request.setTransferProgress(progressCallback);
auto outcome = client->ResumableDownloadObject(request);
if (outcome.isSuccess()) {
std::cout << __FUNCTION__ << "[" << this << "]" << " success, ETag:" << outcome.result().Metadata().ETag() << std::endl;
}
else {
PrintError(__FUNCTION__, outcome.error());
}
}
测试时遇到的两个问题
添加<windows.h>头文件时无法识别外部链接GetObjectW
添加<windows.h>头文件时,会提示无法识别外部链接GetObjectW的问题此时只需要:
添加3个undef语句,避免了调用OSS::GetObject时编译报错
#include <Windows.h>
#undef GetObject
#undef GetObjectW
#undef GetObjectA
阿里云OSS C++SDK在VS15编译提示无法识别外部链接GetObjectW的解决办法
在添加进度条下载功能时,静态方法发送信号
当测试下载进度时,需要ProgressCallback方法中发送信号,而ProgressCallback方法是个静态方法,解决方法是在ProgressCallback中调用个单例类来单独发送信息,而这个单例类与线程类绑定信号;下载的暂停同样是在ProgressCallback中实现。