| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- #include <stdlib.h>
- #include <sys/stat.h>
- #include <iostream>
- #include <map>
- #include <string>
- #include <thread>
- #include <vector>
- #include "cos_api.h"
- #include "cos_sys_config.h"
- #include "util/auth_tool.h"
- // #include <openssl/ssl.h> // 双向认证引用头
- /**
- * 本样例演示了如何使用 COS C++ SDK 进行对象的高级上传
- * 包括:高级上传接口(多线程、支持断点续传功能)、异步高级上传接口、异步简单上传接口(流&文件)、分块上传(用户自行调用初始化、上传、完成分块接口)
- */
- using namespace qcloud_cos;
- uint64_t appid = 12500000000;
- std::string tmp_secret_id = "AKIDXXXXXXXX";
- std::string tmp_secret_key = "1A2Z3YYYYYYYYYY";
- std::string region = "ap-guangzhou";
- std::string bucket_name = "examplebucket-12500000000";
- std::string tmp_token = "token";
- /*
- * 本方法包含调用是否正常的判断,和请求结果的输出
- * 可通过本方法判断是否请求成功,并输出结果信息
- */
- void PrintResult(const qcloud_cos::CosResult& result, const qcloud_cos::BaseResp& resp) {
- if (result.IsSucc()) {
- std::cout << "Request Succ." << std::endl;
- std::cout << resp.DebugString() << std::endl;
- } else {
- std::cout << "ErrorMsg=" << result.GetErrorMsg() << std::endl;
- std::cout << "HttpStatus=" << result.GetHttpStatus() << std::endl;
- std::cout << "ErrorCode=" << result.GetErrorCode() << std::endl;
- std::cout << "ErrorMsg=" << result.GetErrorMsg() << std::endl;
- std::cout << "ResourceAddr=" << result.GetResourceAddr() << std::endl;
- std::cout << "XCosRequestId=" << result.GetXCosRequestId() << std::endl;
- std::cout << "XCosTraceId=" << result.GetXCosTraceId() << std::endl;
- }
- }
- /*
- * 通过参数形式初始化 CosAPI 对象
- */
- qcloud_cos::CosAPI InitCosAPI() {
- qcloud_cos::CosConfig config(appid, tmp_secret_id, tmp_secret_key, region);
- config.SetTmpToken(tmp_token); // 推荐使用临时密钥初始化 CosAPI 对象, 如果您使用永久密钥初始化 CosAPI 对象,请注释
- // config.SetDestDomain("xxx.xxxx.com"); // 配置自定义域名
- // config.SetDomainSameToHost(true); // 配置自定义域名签名
- qcloud_cos::CosAPI cos_tmp(config);
- return cos_tmp;
- }
- /**
- * 本方法为 SSL_CTX 的回调方法,用户可以在此方法中配置 SSL_CTX 信息
- */
- // int SslCtxCallback(void *ssl_ctx, void *data) {
- // std::cout << "ssl_ctx: " << ssl_ctx << " data: " << data << std::endl;
- // SSL_CTX *ctx = (SSL_CTX *)ssl_ctx;
- // std::cout << "ssl_ctx in" << std::endl;
- // SSL_CTX_use_PrivateKey_file(ctx, "/data/cert/client.key", SSL_FILETYPE_PEM);
- // SSL_CTX_use_certificate_chain_file(ctx, "/data/cert/client.crt");
- // std::cout << "ssl_ctx out" << std::endl;
- // return 0;
- // }
- /*
- * 该 Demo 示范如何使用高级上传接口进行对象上传
- * 仅支持文件上传,不支持流式上传,封装了分块上传的各接口
- * 可通过全局设置上传线程池大小、分块大小。该上传线程池是每次上传独立的。
- */
- void MultiUploadObjectDemo(qcloud_cos::CosAPI& cos) {
- std::string local_file = "test_file/big_file.txt";
- std::string object_name = "big_file.txt";
- // 此配置是全局性配置,主动设置后,后续的高级上传,都使用此配置
- CosSysConfig::SetUploadThreadPoolSize(5); // 上传线程池大小 默认5
- CosSysConfig::SetUploadPartSize(10 * 1024 * 1024); // 上传分块大小 默认10M
- qcloud_cos::MultiPutObjectReq req(bucket_name, object_name, local_file);
- // req.SetHttps(); // 设置 https 请求
- // req.SetSSLCtxCallback(SslCtxCallback, nullptr); //双向认证回调
- qcloud_cos::MultiPutObjectResp resp;
- qcloud_cos::CosResult result = cos.MultiPutObject(req, &resp);
- std::cout << "===================MultiUploadObject=======================" << std::endl;
- if (result.IsSucc()) {
- std::cout << "MultiUpload Succ." << std::endl;
- std::cout << resp.GetLocation() << std::endl;
- std::cout << resp.GetKey() << std::endl;
- std::cout << resp.GetBucket() << std::endl;
- std::cout << resp.GetEtag() << std::endl;
- } else {
- std::cout << "MultiUpload Fail." << std::endl;
- // 获取具体失败在哪一步
- std::string resp_tag = resp.GetRespTag();
- if ("Init" == resp_tag) {
- // print result
- } else if ("Upload" == resp_tag) {
- // print result
- } else if ("Complete" == resp_tag) {
- // print result
- }
- PrintResult(result, resp);
- }
- std::cout << "===========================================================" << std::endl;
- }
- /*
- * 该方法是异步上传对象的进度回调示例
- */
- void ProgressCallback(uint64_t transferred_size, uint64_t total_size, void* user_data) {
- qcloud_cos::ObjectReq* req = static_cast<qcloud_cos::ObjectReq*>(user_data);
- if (0 == transferred_size % 1048576) {
- std::cout << "ObjectName:" << req->GetObjectName() << ", TranferedSize:" << transferred_size << ",TotalSize:" << total_size << std::endl;
- }
- }
- /*
- * 该方法是异步上传对象的完成回调示例
- */
- void PutObjectAsyncDoneCallback(const SharedAsyncContext& context, void* user_data) {
- UNUSED_PARAM(user_data)
- std::cout << "PutObjectAsyncDoneCallback, BucketName:" << context->GetBucketName() << ", ObjectName:" << context->GetObjectName() << ", LocalFile:" << context->GetLocalFilePath() << std::endl;
- if (context->GetResult().IsSucc()) {
- // 获取响应
- std::cout << "AsyncMultiPutObject succeed" << std::endl;
- std::cout << "Result:" << context->GetResult().DebugString() << std::endl;
- AsyncResp resp = context->GetAsyncResp();
- // std::cout << "Location:" << resp.GetLocation() << std::endl;
- // std::cout << "Bucket:" << resp.GetBucket() << std::endl;
- // std::cout << "Key:" << resp.GetKey() << std::endl;
- std::cout << "ETag:" << resp.GetEtag() << std::endl;
- std::cout << "Crc64:" << resp.GetXCosHashCrc64Ecma() << std::endl;
- } else {
- std::cout << "AsyncMultiGetObject failed" << std::endl;
- std::cout << "ErrorMsg:" << context->GetResult().GetErrorMsg() << std::endl;
- }
- }
- /*
- * 该 Demo 示范如何通过异步高级上传对象进行对象上传
- * 仅支持文件上传,不支持流式上传,封装了分块上传的各接口、
- * 可通过全局设置异步线程池大小、上传线程池大小、分块大小
- * 注意:异步线程池是全局共用的,供异步调用使用。上传线程池、分块大小是和高级接口共用配置
- * 例如调用两次异步接口,则两个异步操作会使用异步线程池进行调度。而每个异步操作会调用高级接口创建出供本次使用的上传线程池,从而并发上传对象。
- * 支持上传进度回调和上传状态回调
- */
- void AsyncMultiPutObjectDemo(qcloud_cos::CosAPI& cos) {
- std::string local_file = "test_file/big_file.txt";
- std::string object_name = "big_file.txt";
- qcloud_cos::AsyncMultiPutObjectReq req(bucket_name, object_name, local_file);
- req.SetRecvTimeoutInms(1000 * 60);
- // 设置上传进度回调
- req.SetTransferProgressCallback(&ProgressCallback);
- // 设置上传状态回调
- req.SetDoneCallback(&PutObjectAsyncDoneCallback);
- // 设置私有数据,对应回调中的 user_data
- req.SetUserData(&req);
- // 开始上传
- SharedAsyncContext context = cos.AsyncMultiPutObject(req);
- std::cout << "===================AsyncMultiPutObject======================" << std::endl;
- // 等待上传结束
- std::cout << "wait finish..." << std::endl;
- context->WaitUntilFinish();
- // 检查结果
- if (context->GetResult().IsSucc()) {
- // 获取响应
- std::cout << "AsyncMultiPutObject succeed" << std::endl;
- std::cout << "Result:" << context->GetResult().DebugString() << std::endl;
- AsyncResp resp = context->GetAsyncResp();
- // std::cout << "Location:" << resp.GetLocation() << std::endl;
- // std::cout << "Bucket:" << resp.GetBucket() << std::endl;
- // std::cout << "Key:" << resp.GetKey() << std::endl;
- std::cout << "ETag:" << resp.GetEtag() << std::endl;
- std::cout << "Crc64:" << resp.GetXCosHashCrc64Ecma() << std::endl;
- } else {
- std::cout << "AsyncMultiPutObject failed" << std::endl;
- std::cout << "ErrorMsg:" << context->GetResult().GetErrorMsg() << std::endl;
- }
- std::cout << "============================================================" << std::endl;
- }
- /*
- * 该 Demo 示范如何通过异步普通接口上传对象
- * 包括流和文件两种方式上传
- * 可通过全局设置异步线程池大小
- * 注意:异步线程池是全局共用的,供异步调用使用
- * 例如调用两次异步接口,则两个异步操作会使用异步线程池进行调度
- * 支持上传进度回调和上传状态回调
- */
- void AsyncPutObjectDemo(qcloud_cos::CosAPI& cos) {
- // 流上传
- {
- std::string object_name = "text.txt";
- std::istringstream iss("put object");
- qcloud_cos::AsyncPutObjectByStreamReq req(bucket_name, object_name, iss);
- req.SetRecvTimeoutInms(1000 * 60);
- // 设置上传进度回调
- req.SetTransferProgressCallback(&ProgressCallback);
- // 设置上传状态回调
- req.SetDoneCallback(&PutObjectAsyncDoneCallback);
- // 设置私有数据,对应回调中的 user_data
- req.SetUserData(&req);
- // 开始上传
- SharedAsyncContext context = cos.AsyncPutObject(req);
- std::cout << "===================AsyncPutObjectByStream======================" << std::endl;
- // 等待上传结束
- std::cout << "wait finish..." << std::endl;
- context->WaitUntilFinish();
- // 检查结果
- if (context->GetResult().IsSucc()) {
- // 获取响应
- std::cout << "AsyncPutObjectByStream succeed" << std::endl;
- std::cout << "Result:" << context->GetResult().DebugString() << std::endl;
- AsyncResp resp = context->GetAsyncResp();
- // std::cout << "Location:" << resp.GetLocation() << std::endl;
- // std::cout << "Bucket:" << resp.GetBucket() << std::endl;
- // std::cout << "Key:" << resp.GetKey() << std::endl;
- std::cout << "ETag:" << resp.GetEtag() << std::endl;
- std::cout << "Crc64:" << resp.GetXCosHashCrc64Ecma() << std::endl;
- } else {
- std::cout << "AsyncPutObjectByStream failed" << std::endl;
- std::cout << "ErrorMsg:" << context->GetResult().GetErrorMsg() << std::endl;
- }
- std::cout << "===============================================================" << std::endl;
- }
- // 文件上传
- {
- std::string local_file = "test_file/text.txt";
- std::string object_name = "text.txt";
- qcloud_cos::AsyncPutObjectReq req(bucket_name, object_name, local_file);
- req.SetRecvTimeoutInms(1000 * 60);
- // 设置上传进度回调
- req.SetTransferProgressCallback(&ProgressCallback);
- // 设置上传状态回调
- req.SetDoneCallback(&PutObjectAsyncDoneCallback);
- // 设置私有数据,对应回调中的 user_data
- req.SetUserData(&req);
- // 开始上传
- SharedAsyncContext context = cos.AsyncPutObject(req);
- std::cout << "===================AsyncPutObjectByFile======================" << std::endl;
- // 等待上传结束
- std::cout << "wait finish..." << std::endl;
- context->WaitUntilFinish();
- // 检查结果
- if (context->GetResult().IsSucc()) {
- // 获取响应
- std::cout << "AsyncPutObjectByFile succeed" << std::endl;
- std::cout << "Result:" << context->GetResult().DebugString() << std::endl;
- AsyncResp resp = context->GetAsyncResp();
- // std::cout << "Location:" << resp.GetLocation() << std::endl;
- // std::cout << "Bucket:" << resp.GetBucket() << std::endl;
- // std::cout << "Key:" << resp.GetKey() << std::endl;
- std::cout << "ETag:" << resp.GetEtag() << std::endl;
- std::cout << "Crc64:" << resp.GetXCosHashCrc64Ecma() << std::endl;
- } else {
- std::cout << "AsyncPutObjectByFile failed" << std::endl;
- std::cout << "ErrorMsg:" << context->GetResult().GetErrorMsg() << std::endl;
- }
- std::cout << "=============================================================" << std::endl;
- }
- }
- /*
- * 该 Demo 示范用户如何自行组合分块上传各接口进行对象上传
- * 分块操作基于初始化、上传分块、完成分块三个接口可以实现将对象切分为多个分块,然后再将这些分块上传到 cos,最后发起 Complete 完成分块上传
- * 本 Demo 中的上传分块接口 UploadPartData 仅支持传入流,最多支持10000分块,每个分块大小为1MB - 5GB,最后一个分块可以小于1MB
- */
- void PutPartDemo(qcloud_cos::CosAPI& cos) {
- std::string object_name = "big_file.txt";
- // 1. InitMultiUpload
- qcloud_cos::InitMultiUploadReq init_req(bucket_name, object_name);
- qcloud_cos::InitMultiUploadResp init_resp;
- qcloud_cos::CosResult init_result = cos.InitMultiUpload(init_req, &init_resp);
- std::cout << "=====================InitMultiUpload=====================" << std::endl;
- PrintResult(init_result, init_resp);
- std::cout << "=========================================================" << std::endl;
- // 2. UploadPartData
- // UploadPartData 部分,可以根据实际选择分块数量和分块大小,这里以 2 个分块为例
- // Complete 需要的两个列表:
- std::vector<std::string> etags;
- std::vector<uint64_t> part_numbers;
- std::string upload_id = init_resp.GetUploadId();
- {
- uint64_t part_number = 1;
- // 模拟上传分块数据,这里以 100M 为例
- uint64_t copy_size = 1024 * 1024 * 100;
- std::vector<char> data(copy_size, 'A');
- std::string content(data.begin(), data.end());
- std::istringstream iss(content);
- qcloud_cos::UploadPartDataReq req(bucket_name, object_name, upload_id, iss);
- req.SetPartNumber(part_number);
- // 限速上传对象,默认单位为 bit/s,限速值设置范围为 819200 - 838860800, 即800Kb/s-800Mb/s
- uint64_t traffic_limit = 8192*1024*10; // 100MB 文件 5M
- req.SetTrafficLimit(traffic_limit);
- qcloud_cos::UploadPartDataResp resp;
- std::chrono::time_point<std::chrono::steady_clock> start_ts, end_ts;
- start_ts = std::chrono::steady_clock::now();
- qcloud_cos::CosResult result = cos.UploadPartData(req, &resp);
- end_ts = std::chrono::steady_clock::now();
- auto time_consumed_ms =
- std::chrono::duration_cast<std::chrono::milliseconds>(end_ts - start_ts)
- .count();
- float rate =
- ((float)copy_size / 1024 / 1024) / ((float)time_consumed_ms / 1000);
- SDK_LOG_ERR("send part_number: %d, send_size: %" PRIu64 " MB, time_consumed: %" PRIu64
- " ms, rate: %.2f MB/s , traffic_limit : %.2f MB", part_number, copy_size/ 1024 / 1024, time_consumed_ms, rate, traffic_limit/1024/1024/8.0);
- std::cout << "==================UploadPartDataResp1=====================" << std::endl;
- PrintResult(result, resp);
- std::cout << "==========================================================" << std::endl;
- if (result.IsSucc()) {
- part_numbers.push_back(part_number);
- etags.push_back(resp.GetEtag());
- }
- }
- {
- uint64_t part_number = 2;
- uint64_t copy_size = 1024 * 1024 * 100;
- std::vector<char> data(copy_size, 'A');
- std::string content(data.begin(), data.end());
- std::istringstream iss(content);
- qcloud_cos::UploadPartDataReq req(bucket_name, object_name, upload_id, iss);
- req.SetPartNumber(part_number);
- // 限速上传对象,默认单位为 bit/s,限速值设置范围为 819200 - 838860800, 即800Kb/s-800Mb/s
- uint64_t traffic_limit = 8192 * 1024 * 5 ;
- req.SetTrafficLimit(traffic_limit);
- qcloud_cos::UploadPartDataResp resp;
- qcloud_cos::CosResult result = cos.UploadPartData(req, &resp);
- std::cout << "==================UploadPartDataResp2=====================" << std::endl;
- PrintResult(result, resp);
- std::cout << "==========================================================" << std::endl;
- if (result.IsSucc()) {
- part_numbers.push_back(part_number);
- etags.push_back(resp.GetEtag());
- }
- }
- {
- uint64_t part_number = 3;
- uint64_t copy_size = 1024 * 1024 * 10;
- std::vector<char> data(copy_size, 'A');
- std::string content(data.begin(), data.end());
- std::istringstream iss(content);
- qcloud_cos::UploadPartDataReq req(bucket_name, object_name, upload_id, iss);
- req.SetPartNumber(part_number);
- // 限速上传对象,默认单位为 bit/s,限速值设置范围为 819200 - 838860800, 即800Kb/s-800Mb/s
- uint64_t traffic_limit = 8192 * 1024;
- req.SetTrafficLimit(traffic_limit);
- qcloud_cos::UploadPartDataResp resp;
- qcloud_cos::CosResult result = cos.UploadPartData(req, &resp);
- std::cout << "==================UploadPartDataResp2=====================" << std::endl;
- PrintResult(result, resp);
- std::cout << "==========================================================" << std::endl;
- if (result.IsSucc()) {
- part_numbers.push_back(part_number);
- etags.push_back(resp.GetEtag());
- }
- }
- // 3. Complete
- CompleteMultiUploadReq comp_req(bucket_name, object_name, upload_id);
- CompleteMultiUploadResp comp_resp;
- comp_req.SetEtags(etags);
- comp_req.SetPartNumbers(part_numbers);
- qcloud_cos::CosResult result = cos.CompleteMultiUpload(comp_req, &comp_resp);
- std::cout << "===================Complete=============================" << std::endl;
- PrintResult(result, comp_resp);
- std::cout << "========================================================" << std::endl;
- return;
- }
- void PutObjectResumableSingleThreadSyncDemo(qcloud_cos::CosAPI& cos) {
- std::string local_file = "SingleThreadSync.txt";
- std::string object_name = "SingleThreadSync.txt";
- qcloud_cos::PutObjectResumableSingleSyncReq req(bucket_name, object_name, local_file);
- req.AddHeader("x-cos-meta-ssss1","1xxxxxxx");
- req.AddHeader("x-cos-meta-ssss2","2xxxxxxx");
- req.AddHeader("x-cos-meta-ssss3","3xxxxxxx");
- req.AddHeader("x-cos-meta-ssss4","4xxxxxxx");
- uint64_t traffic_limit = 8192 * 1024;//1MB
- req.SetTrafficLimit(traffic_limit);
- //req.SetHttps();
- //req.SetSSLCtxCallback(SslCtxCallback, nullptr);
- qcloud_cos::PutObjectResumableSingleSyncResp resp;
- qcloud_cos::CosResult result = cos.PutObjectResumableSingleThreadSync(req, &resp);
- if (result.IsSucc()) {
- std::cout << "MultiUpload Succ." << std::endl;
- std::cout << resp.GetLocation() << std::endl;
- std::cout << resp.GetKey() << std::endl;
- std::cout << resp.GetBucket() << std::endl;
- std::cout << resp.GetEtag() << std::endl;
- } else {
- std::cout << "MultiUpload Fail." << std::endl;
- // 获取具体失败在哪一步
- std::string resp_tag = resp.GetRespTag();
- if ("Init" == resp_tag) {
- // print result
- } else if ("Upload" == resp_tag) {
- // print result
- } else if ("Complete" == resp_tag) {
- // print result
- }
- PrintResult(result, resp);
- }
- std::cout << "===========================================================" << std::endl;
- }
- int main() {
- qcloud_cos::CosAPI cos = InitCosAPI();
- CosSysConfig::SetLogLevel((LOG_LEVEL)COS_LOG_ERR);
- MultiUploadObjectDemo(cos);
- AsyncMultiPutObjectDemo(cos);
- AsyncPutObjectDemo(cos);
- PutPartDemo(cos);
- PutObjectResumableSingleThreadSyncDemo(cos);
- }
|