multi_put_object_demo.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. #include <stdlib.h>
  2. #include <sys/stat.h>
  3. #include <iostream>
  4. #include <map>
  5. #include <string>
  6. #include <thread>
  7. #include <vector>
  8. #include "cos_api.h"
  9. #include "cos_sys_config.h"
  10. #include "util/auth_tool.h"
  11. // #include <openssl/ssl.h> // 双向认证引用头
  12. /**
  13. * 本样例演示了如何使用 COS C++ SDK 进行对象的高级上传
  14. * 包括:高级上传接口(多线程、支持断点续传功能)、异步高级上传接口、异步简单上传接口(流&文件)、分块上传(用户自行调用初始化、上传、完成分块接口)
  15. */
  16. using namespace qcloud_cos;
  17. uint64_t appid = 12500000000;
  18. std::string tmp_secret_id = "AKIDXXXXXXXX";
  19. std::string tmp_secret_key = "1A2Z3YYYYYYYYYY";
  20. std::string region = "ap-guangzhou";
  21. std::string bucket_name = "examplebucket-12500000000";
  22. std::string tmp_token = "token";
  23. /*
  24. * 本方法包含调用是否正常的判断,和请求结果的输出
  25. * 可通过本方法判断是否请求成功,并输出结果信息
  26. */
  27. void PrintResult(const qcloud_cos::CosResult& result, const qcloud_cos::BaseResp& resp) {
  28. if (result.IsSucc()) {
  29. std::cout << "Request Succ." << std::endl;
  30. std::cout << resp.DebugString() << std::endl;
  31. } else {
  32. std::cout << "ErrorMsg=" << result.GetErrorMsg() << std::endl;
  33. std::cout << "HttpStatus=" << result.GetHttpStatus() << std::endl;
  34. std::cout << "ErrorCode=" << result.GetErrorCode() << std::endl;
  35. std::cout << "ErrorMsg=" << result.GetErrorMsg() << std::endl;
  36. std::cout << "ResourceAddr=" << result.GetResourceAddr() << std::endl;
  37. std::cout << "XCosRequestId=" << result.GetXCosRequestId() << std::endl;
  38. std::cout << "XCosTraceId=" << result.GetXCosTraceId() << std::endl;
  39. }
  40. }
  41. /*
  42. * 通过参数形式初始化 CosAPI 对象
  43. */
  44. qcloud_cos::CosAPI InitCosAPI() {
  45. qcloud_cos::CosConfig config(appid, tmp_secret_id, tmp_secret_key, region);
  46. config.SetTmpToken(tmp_token); // 推荐使用临时密钥初始化 CosAPI 对象, 如果您使用永久密钥初始化 CosAPI 对象,请注释
  47. // config.SetDestDomain("xxx.xxxx.com"); // 配置自定义域名
  48. // config.SetDomainSameToHost(true); // 配置自定义域名签名
  49. qcloud_cos::CosAPI cos_tmp(config);
  50. return cos_tmp;
  51. }
  52. /**
  53. * 本方法为 SSL_CTX 的回调方法,用户可以在此方法中配置 SSL_CTX 信息
  54. */
  55. // int SslCtxCallback(void *ssl_ctx, void *data) {
  56. // std::cout << "ssl_ctx: " << ssl_ctx << " data: " << data << std::endl;
  57. // SSL_CTX *ctx = (SSL_CTX *)ssl_ctx;
  58. // std::cout << "ssl_ctx in" << std::endl;
  59. // SSL_CTX_use_PrivateKey_file(ctx, "/data/cert/client.key", SSL_FILETYPE_PEM);
  60. // SSL_CTX_use_certificate_chain_file(ctx, "/data/cert/client.crt");
  61. // std::cout << "ssl_ctx out" << std::endl;
  62. // return 0;
  63. // }
  64. /*
  65. * 该 Demo 示范如何使用高级上传接口进行对象上传
  66. * 仅支持文件上传,不支持流式上传,封装了分块上传的各接口
  67. * 可通过全局设置上传线程池大小、分块大小。该上传线程池是每次上传独立的。
  68. */
  69. void MultiUploadObjectDemo(qcloud_cos::CosAPI& cos) {
  70. std::string local_file = "test_file/big_file.txt";
  71. std::string object_name = "big_file.txt";
  72. // 此配置是全局性配置,主动设置后,后续的高级上传,都使用此配置
  73. CosSysConfig::SetUploadThreadPoolSize(5); // 上传线程池大小 默认5
  74. CosSysConfig::SetUploadPartSize(10 * 1024 * 1024); // 上传分块大小 默认10M
  75. qcloud_cos::MultiPutObjectReq req(bucket_name, object_name, local_file);
  76. // req.SetHttps(); // 设置 https 请求
  77. // req.SetSSLCtxCallback(SslCtxCallback, nullptr); //双向认证回调
  78. qcloud_cos::MultiPutObjectResp resp;
  79. qcloud_cos::CosResult result = cos.MultiPutObject(req, &resp);
  80. std::cout << "===================MultiUploadObject=======================" << std::endl;
  81. if (result.IsSucc()) {
  82. std::cout << "MultiUpload Succ." << std::endl;
  83. std::cout << resp.GetLocation() << std::endl;
  84. std::cout << resp.GetKey() << std::endl;
  85. std::cout << resp.GetBucket() << std::endl;
  86. std::cout << resp.GetEtag() << std::endl;
  87. } else {
  88. std::cout << "MultiUpload Fail." << std::endl;
  89. // 获取具体失败在哪一步
  90. std::string resp_tag = resp.GetRespTag();
  91. if ("Init" == resp_tag) {
  92. // print result
  93. } else if ("Upload" == resp_tag) {
  94. // print result
  95. } else if ("Complete" == resp_tag) {
  96. // print result
  97. }
  98. PrintResult(result, resp);
  99. }
  100. std::cout << "===========================================================" << std::endl;
  101. }
  102. /*
  103. * 该方法是异步上传对象的进度回调示例
  104. */
  105. void ProgressCallback(uint64_t transferred_size, uint64_t total_size, void* user_data) {
  106. qcloud_cos::ObjectReq* req = static_cast<qcloud_cos::ObjectReq*>(user_data);
  107. if (0 == transferred_size % 1048576) {
  108. std::cout << "ObjectName:" << req->GetObjectName() << ", TranferedSize:" << transferred_size << ",TotalSize:" << total_size << std::endl;
  109. }
  110. }
  111. /*
  112. * 该方法是异步上传对象的完成回调示例
  113. */
  114. void PutObjectAsyncDoneCallback(const SharedAsyncContext& context, void* user_data) {
  115. UNUSED_PARAM(user_data)
  116. std::cout << "PutObjectAsyncDoneCallback, BucketName:" << context->GetBucketName() << ", ObjectName:" << context->GetObjectName() << ", LocalFile:" << context->GetLocalFilePath() << std::endl;
  117. if (context->GetResult().IsSucc()) {
  118. // 获取响应
  119. std::cout << "AsyncMultiPutObject succeed" << std::endl;
  120. std::cout << "Result:" << context->GetResult().DebugString() << std::endl;
  121. AsyncResp resp = context->GetAsyncResp();
  122. // std::cout << "Location:" << resp.GetLocation() << std::endl;
  123. // std::cout << "Bucket:" << resp.GetBucket() << std::endl;
  124. // std::cout << "Key:" << resp.GetKey() << std::endl;
  125. std::cout << "ETag:" << resp.GetEtag() << std::endl;
  126. std::cout << "Crc64:" << resp.GetXCosHashCrc64Ecma() << std::endl;
  127. } else {
  128. std::cout << "AsyncMultiGetObject failed" << std::endl;
  129. std::cout << "ErrorMsg:" << context->GetResult().GetErrorMsg() << std::endl;
  130. }
  131. }
  132. /*
  133. * 该 Demo 示范如何通过异步高级上传对象进行对象上传
  134. * 仅支持文件上传,不支持流式上传,封装了分块上传的各接口、
  135. * 可通过全局设置异步线程池大小、上传线程池大小、分块大小
  136. * 注意:异步线程池是全局共用的,供异步调用使用。上传线程池、分块大小是和高级接口共用配置
  137. * 例如调用两次异步接口,则两个异步操作会使用异步线程池进行调度。而每个异步操作会调用高级接口创建出供本次使用的上传线程池,从而并发上传对象。
  138. * 支持上传进度回调和上传状态回调
  139. */
  140. void AsyncMultiPutObjectDemo(qcloud_cos::CosAPI& cos) {
  141. std::string local_file = "test_file/big_file.txt";
  142. std::string object_name = "big_file.txt";
  143. qcloud_cos::AsyncMultiPutObjectReq req(bucket_name, object_name, local_file);
  144. req.SetRecvTimeoutInms(1000 * 60);
  145. // 设置上传进度回调
  146. req.SetTransferProgressCallback(&ProgressCallback);
  147. // 设置上传状态回调
  148. req.SetDoneCallback(&PutObjectAsyncDoneCallback);
  149. // 设置私有数据,对应回调中的 user_data
  150. req.SetUserData(&req);
  151. // 开始上传
  152. SharedAsyncContext context = cos.AsyncMultiPutObject(req);
  153. std::cout << "===================AsyncMultiPutObject======================" << std::endl;
  154. // 等待上传结束
  155. std::cout << "wait finish..." << std::endl;
  156. context->WaitUntilFinish();
  157. // 检查结果
  158. if (context->GetResult().IsSucc()) {
  159. // 获取响应
  160. std::cout << "AsyncMultiPutObject succeed" << std::endl;
  161. std::cout << "Result:" << context->GetResult().DebugString() << std::endl;
  162. AsyncResp resp = context->GetAsyncResp();
  163. // std::cout << "Location:" << resp.GetLocation() << std::endl;
  164. // std::cout << "Bucket:" << resp.GetBucket() << std::endl;
  165. // std::cout << "Key:" << resp.GetKey() << std::endl;
  166. std::cout << "ETag:" << resp.GetEtag() << std::endl;
  167. std::cout << "Crc64:" << resp.GetXCosHashCrc64Ecma() << std::endl;
  168. } else {
  169. std::cout << "AsyncMultiPutObject failed" << std::endl;
  170. std::cout << "ErrorMsg:" << context->GetResult().GetErrorMsg() << std::endl;
  171. }
  172. std::cout << "============================================================" << std::endl;
  173. }
  174. /*
  175. * 该 Demo 示范如何通过异步普通接口上传对象
  176. * 包括流和文件两种方式上传
  177. * 可通过全局设置异步线程池大小
  178. * 注意:异步线程池是全局共用的,供异步调用使用
  179. * 例如调用两次异步接口,则两个异步操作会使用异步线程池进行调度
  180. * 支持上传进度回调和上传状态回调
  181. */
  182. void AsyncPutObjectDemo(qcloud_cos::CosAPI& cos) {
  183. // 流上传
  184. {
  185. std::string object_name = "text.txt";
  186. std::istringstream iss("put object");
  187. qcloud_cos::AsyncPutObjectByStreamReq req(bucket_name, object_name, iss);
  188. req.SetRecvTimeoutInms(1000 * 60);
  189. // 设置上传进度回调
  190. req.SetTransferProgressCallback(&ProgressCallback);
  191. // 设置上传状态回调
  192. req.SetDoneCallback(&PutObjectAsyncDoneCallback);
  193. // 设置私有数据,对应回调中的 user_data
  194. req.SetUserData(&req);
  195. // 开始上传
  196. SharedAsyncContext context = cos.AsyncPutObject(req);
  197. std::cout << "===================AsyncPutObjectByStream======================" << std::endl;
  198. // 等待上传结束
  199. std::cout << "wait finish..." << std::endl;
  200. context->WaitUntilFinish();
  201. // 检查结果
  202. if (context->GetResult().IsSucc()) {
  203. // 获取响应
  204. std::cout << "AsyncPutObjectByStream succeed" << std::endl;
  205. std::cout << "Result:" << context->GetResult().DebugString() << std::endl;
  206. AsyncResp resp = context->GetAsyncResp();
  207. // std::cout << "Location:" << resp.GetLocation() << std::endl;
  208. // std::cout << "Bucket:" << resp.GetBucket() << std::endl;
  209. // std::cout << "Key:" << resp.GetKey() << std::endl;
  210. std::cout << "ETag:" << resp.GetEtag() << std::endl;
  211. std::cout << "Crc64:" << resp.GetXCosHashCrc64Ecma() << std::endl;
  212. } else {
  213. std::cout << "AsyncPutObjectByStream failed" << std::endl;
  214. std::cout << "ErrorMsg:" << context->GetResult().GetErrorMsg() << std::endl;
  215. }
  216. std::cout << "===============================================================" << std::endl;
  217. }
  218. // 文件上传
  219. {
  220. std::string local_file = "test_file/text.txt";
  221. std::string object_name = "text.txt";
  222. qcloud_cos::AsyncPutObjectReq req(bucket_name, object_name, local_file);
  223. req.SetRecvTimeoutInms(1000 * 60);
  224. // 设置上传进度回调
  225. req.SetTransferProgressCallback(&ProgressCallback);
  226. // 设置上传状态回调
  227. req.SetDoneCallback(&PutObjectAsyncDoneCallback);
  228. // 设置私有数据,对应回调中的 user_data
  229. req.SetUserData(&req);
  230. // 开始上传
  231. SharedAsyncContext context = cos.AsyncPutObject(req);
  232. std::cout << "===================AsyncPutObjectByFile======================" << std::endl;
  233. // 等待上传结束
  234. std::cout << "wait finish..." << std::endl;
  235. context->WaitUntilFinish();
  236. // 检查结果
  237. if (context->GetResult().IsSucc()) {
  238. // 获取响应
  239. std::cout << "AsyncPutObjectByFile succeed" << std::endl;
  240. std::cout << "Result:" << context->GetResult().DebugString() << std::endl;
  241. AsyncResp resp = context->GetAsyncResp();
  242. // std::cout << "Location:" << resp.GetLocation() << std::endl;
  243. // std::cout << "Bucket:" << resp.GetBucket() << std::endl;
  244. // std::cout << "Key:" << resp.GetKey() << std::endl;
  245. std::cout << "ETag:" << resp.GetEtag() << std::endl;
  246. std::cout << "Crc64:" << resp.GetXCosHashCrc64Ecma() << std::endl;
  247. } else {
  248. std::cout << "AsyncPutObjectByFile failed" << std::endl;
  249. std::cout << "ErrorMsg:" << context->GetResult().GetErrorMsg() << std::endl;
  250. }
  251. std::cout << "=============================================================" << std::endl;
  252. }
  253. }
  254. /*
  255. * 该 Demo 示范用户如何自行组合分块上传各接口进行对象上传
  256. * 分块操作基于初始化、上传分块、完成分块三个接口可以实现将对象切分为多个分块,然后再将这些分块上传到 cos,最后发起 Complete 完成分块上传
  257. * 本 Demo 中的上传分块接口 UploadPartData 仅支持传入流,最多支持10000分块,每个分块大小为1MB - 5GB,最后一个分块可以小于1MB
  258. */
  259. void PutPartDemo(qcloud_cos::CosAPI& cos) {
  260. std::string object_name = "big_file.txt";
  261. // 1. InitMultiUpload
  262. qcloud_cos::InitMultiUploadReq init_req(bucket_name, object_name);
  263. qcloud_cos::InitMultiUploadResp init_resp;
  264. qcloud_cos::CosResult init_result = cos.InitMultiUpload(init_req, &init_resp);
  265. std::cout << "=====================InitMultiUpload=====================" << std::endl;
  266. PrintResult(init_result, init_resp);
  267. std::cout << "=========================================================" << std::endl;
  268. // 2. UploadPartData
  269. // UploadPartData 部分,可以根据实际选择分块数量和分块大小,这里以 2 个分块为例
  270. // Complete 需要的两个列表:
  271. std::vector<std::string> etags;
  272. std::vector<uint64_t> part_numbers;
  273. std::string upload_id = init_resp.GetUploadId();
  274. {
  275. uint64_t part_number = 1;
  276. // 模拟上传分块数据,这里以 100M 为例
  277. uint64_t copy_size = 1024 * 1024 * 100;
  278. std::vector<char> data(copy_size, 'A');
  279. std::string content(data.begin(), data.end());
  280. std::istringstream iss(content);
  281. qcloud_cos::UploadPartDataReq req(bucket_name, object_name, upload_id, iss);
  282. req.SetPartNumber(part_number);
  283. // 限速上传对象,默认单位为 bit/s,限速值设置范围为 819200 - 838860800, 即800Kb/s-800Mb/s
  284. uint64_t traffic_limit = 8192*1024*10; // 100MB 文件 5M
  285. req.SetTrafficLimit(traffic_limit);
  286. qcloud_cos::UploadPartDataResp resp;
  287. std::chrono::time_point<std::chrono::steady_clock> start_ts, end_ts;
  288. start_ts = std::chrono::steady_clock::now();
  289. qcloud_cos::CosResult result = cos.UploadPartData(req, &resp);
  290. end_ts = std::chrono::steady_clock::now();
  291. auto time_consumed_ms =
  292. std::chrono::duration_cast<std::chrono::milliseconds>(end_ts - start_ts)
  293. .count();
  294. float rate =
  295. ((float)copy_size / 1024 / 1024) / ((float)time_consumed_ms / 1000);
  296. SDK_LOG_ERR("send part_number: %d, send_size: %" PRIu64 " MB, time_consumed: %" PRIu64
  297. " 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);
  298. std::cout << "==================UploadPartDataResp1=====================" << std::endl;
  299. PrintResult(result, resp);
  300. std::cout << "==========================================================" << std::endl;
  301. if (result.IsSucc()) {
  302. part_numbers.push_back(part_number);
  303. etags.push_back(resp.GetEtag());
  304. }
  305. }
  306. {
  307. uint64_t part_number = 2;
  308. uint64_t copy_size = 1024 * 1024 * 100;
  309. std::vector<char> data(copy_size, 'A');
  310. std::string content(data.begin(), data.end());
  311. std::istringstream iss(content);
  312. qcloud_cos::UploadPartDataReq req(bucket_name, object_name, upload_id, iss);
  313. req.SetPartNumber(part_number);
  314. // 限速上传对象,默认单位为 bit/s,限速值设置范围为 819200 - 838860800, 即800Kb/s-800Mb/s
  315. uint64_t traffic_limit = 8192 * 1024 * 5 ;
  316. req.SetTrafficLimit(traffic_limit);
  317. qcloud_cos::UploadPartDataResp resp;
  318. qcloud_cos::CosResult result = cos.UploadPartData(req, &resp);
  319. std::cout << "==================UploadPartDataResp2=====================" << std::endl;
  320. PrintResult(result, resp);
  321. std::cout << "==========================================================" << std::endl;
  322. if (result.IsSucc()) {
  323. part_numbers.push_back(part_number);
  324. etags.push_back(resp.GetEtag());
  325. }
  326. }
  327. {
  328. uint64_t part_number = 3;
  329. uint64_t copy_size = 1024 * 1024 * 10;
  330. std::vector<char> data(copy_size, 'A');
  331. std::string content(data.begin(), data.end());
  332. std::istringstream iss(content);
  333. qcloud_cos::UploadPartDataReq req(bucket_name, object_name, upload_id, iss);
  334. req.SetPartNumber(part_number);
  335. // 限速上传对象,默认单位为 bit/s,限速值设置范围为 819200 - 838860800, 即800Kb/s-800Mb/s
  336. uint64_t traffic_limit = 8192 * 1024;
  337. req.SetTrafficLimit(traffic_limit);
  338. qcloud_cos::UploadPartDataResp resp;
  339. qcloud_cos::CosResult result = cos.UploadPartData(req, &resp);
  340. std::cout << "==================UploadPartDataResp2=====================" << std::endl;
  341. PrintResult(result, resp);
  342. std::cout << "==========================================================" << std::endl;
  343. if (result.IsSucc()) {
  344. part_numbers.push_back(part_number);
  345. etags.push_back(resp.GetEtag());
  346. }
  347. }
  348. // 3. Complete
  349. CompleteMultiUploadReq comp_req(bucket_name, object_name, upload_id);
  350. CompleteMultiUploadResp comp_resp;
  351. comp_req.SetEtags(etags);
  352. comp_req.SetPartNumbers(part_numbers);
  353. qcloud_cos::CosResult result = cos.CompleteMultiUpload(comp_req, &comp_resp);
  354. std::cout << "===================Complete=============================" << std::endl;
  355. PrintResult(result, comp_resp);
  356. std::cout << "========================================================" << std::endl;
  357. return;
  358. }
  359. void PutObjectResumableSingleThreadSyncDemo(qcloud_cos::CosAPI& cos) {
  360. std::string local_file = "SingleThreadSync.txt";
  361. std::string object_name = "SingleThreadSync.txt";
  362. qcloud_cos::PutObjectResumableSingleSyncReq req(bucket_name, object_name, local_file);
  363. req.AddHeader("x-cos-meta-ssss1","1xxxxxxx");
  364. req.AddHeader("x-cos-meta-ssss2","2xxxxxxx");
  365. req.AddHeader("x-cos-meta-ssss3","3xxxxxxx");
  366. req.AddHeader("x-cos-meta-ssss4","4xxxxxxx");
  367. uint64_t traffic_limit = 8192 * 1024;//1MB
  368. req.SetTrafficLimit(traffic_limit);
  369. //req.SetHttps();
  370. //req.SetSSLCtxCallback(SslCtxCallback, nullptr);
  371. qcloud_cos::PutObjectResumableSingleSyncResp resp;
  372. qcloud_cos::CosResult result = cos.PutObjectResumableSingleThreadSync(req, &resp);
  373. if (result.IsSucc()) {
  374. std::cout << "MultiUpload Succ." << std::endl;
  375. std::cout << resp.GetLocation() << std::endl;
  376. std::cout << resp.GetKey() << std::endl;
  377. std::cout << resp.GetBucket() << std::endl;
  378. std::cout << resp.GetEtag() << std::endl;
  379. } else {
  380. std::cout << "MultiUpload Fail." << std::endl;
  381. // 获取具体失败在哪一步
  382. std::string resp_tag = resp.GetRespTag();
  383. if ("Init" == resp_tag) {
  384. // print result
  385. } else if ("Upload" == resp_tag) {
  386. // print result
  387. } else if ("Complete" == resp_tag) {
  388. // print result
  389. }
  390. PrintResult(result, resp);
  391. }
  392. std::cout << "===========================================================" << std::endl;
  393. }
  394. int main() {
  395. qcloud_cos::CosAPI cos = InitCosAPI();
  396. CosSysConfig::SetLogLevel((LOG_LEVEL)COS_LOG_ERR);
  397. MultiUploadObjectDemo(cos);
  398. AsyncMultiPutObjectDemo(cos);
  399. AsyncPutObjectDemo(cos);
  400. PutPartDemo(cos);
  401. PutObjectResumableSingleThreadSyncDemo(cos);
  402. }