在开始使用 SDK 之前,请确认您已经了解 QingStor 对象存储基本概念,如 Zone,Service,Bucket,Object 等。

使用 SDK 之前请先在 QingCloud 管理控制台申请 Access key 。

配置文件

在使用 SDK 之前,我们需要创建一个本地的配置文件。也可以在初始化 SDK 时通过调用 load_config_from_filepath() 方法来指定具体的配置文件路径。配置文件内可配置项如下所示:

    access_key_id: 'ACCESS_KEY_ID_EXAMPLE'
    secret_access_key: 'SECRET_ACCESS_KEY_EXAMPLE'
    host: 'qingstor.com'
    port: 443
    protocol: 'https'
    connection_retries: 3
    timeOutPeriod: 3

代码片段

  1. 在使用 SDK 之前,需要先初始化全局资源,同时通过一些全局配置参数,指定 SDK 相关的设置:

        // 由入参分别指定 SDK 输出日志的路径、日志级别、 SDK 的 init 过程和 shutdown 过程是否自动初始化和清理 curl 库的全局资源。
        // 其中,有效的日志级别为 None, Fatal, Error, Warning, Info, Debug, Verbose ,默认日志级别为 None ,即不输出日志。
        // 如果在程序中的另外的模块使用了 curl 库,QingStor SDK 自动初始化和清理 curl 库的全局资源,可能会引起这些模块功能产生异常。
        // 这种情况下如果你希望统一管理 curl 全局资源的初始化及清理工作,请将参数设置为 0 ,否则请设置成 1 .
        QingStor::SDKOptions sdkOptions;
        sdkOptions.logLevel = LogLevel::Verbose;
        sdkOptions.logPath = "/tmp/";
        sdkOptions.initAndCleanupCurl = true;
    
        QingStor::InitializeSDK(sdkOptions);
  2. 调用 SDK 接口前,需要先指定访问的 Bucket 和 Zone 信息,创建访问句柄。QingStor 对象存储提供两种创建访问句柄的方式:

    1. 方式一:通过指定配置文件地址,来创建访问句柄。

          QingStor::QsConfig qsConfig;
          qsConfig.LoadConfigFile("/etc/qingstor/config.yaml");
      
          context->pQsService = new QingStorService(qsConfig);
          context->pQsBucket = new Bucket(qsConfig, "yourbucketname", "yourzone");
    2. 方式二:可以通过指定 config 结构,设置具体 config 参数,来创建访问句柄。

          QingStor::QsConfig qsConfig;
      
          // 你可以指定协议类型,请求重试的次数, 以及每次请求超时时间 等配置
          qsConfig.access_key_id = "ACCESS_KEY_ID";
          qsConfig.secret_access_key = "SECRET_ACCESS_KEY";
          qsConfig.protocol = "https";
          qsConfig.conn_retries = 3;
          qsConfig.timeout_period = 10;
      
          // 在私有云环境中,你可以指定实际配置的 host 地址 和服务端口
          // 访问 QingStor 公有云服务, 通常无需更改 host 地址 和服务端口.
          qsConfig.host = "api.private.com";
          qsConfig.port = 4433;
      
          context->pQsService = new QingStorService(qsConfig);
          context->pQsBucket = new Bucket(qsConfig, strBucketName, strZone);
  3. 获取账户下的 Bucket 列表

        ListBucketsInput input;
        ListBucketsOutput output;
    
        QsError err = qsBucket.ListObjects(input, output);
        if (QsError::QS_ERR_NO_ERROR == err)
        {
            // 当返回值为 QS_ERR_NO_ERROR 时,代表得到了符合预期的 response ,可以使用 output 中的信息完成你需要的业务逻辑
            printf("Got response code : %s",output.GetResponseCode());
        }
    
        if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }
  4. 上传一个 Object

        PutObjectInput input;
        PutObjectOutput output;
    
        // object 的内容可以来自于文件 (filestream),可以来自于其他形式的 stream ,只需要保证其为 iostream 的子类.
        std::iostream * objectStream = new std::fstream("/tmp/Screenshot.jpg", std::ios::binary | std::ios::in);
        objectStream->seekg(0, objectStream->end);
        auto streamSize = objectStream->tellg();
        objectStream->seekg(0, objectStream->beg);
        input.SetBody(objectStream);
        input.SetContentLength(streamSize);
    
        QsError err = qsBucket.PutObject(objectKey, input, output);
        if (QsError::QS_ERR_NO_ERROR == err)
        {
            // 当返回值为 QS_ERR_NO_ERROR 时,代表得到了符合预期的 response ,可以使用 output 中的信息完成你需要的业务逻辑
            printf("Got response code : %s",output.GetResponseCode());
        }
    
        if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            ResponseErrorInfo  errorInfo = output.GetResponseErrInfo();
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }
    
        // 释放资源
        if(objectStream)
            delete objectStream;
  5. 列出 Bucket 中的 Objects

        ListObjectsInput input;
        ListObjectsOutput output;
    
        // 设置 response 中返回 object 的数量限制
        input.SetLimit(200);
    
        QsError err = qsBucket.ListObjects(input, output);
        if (QsError::QS_ERR_NO_ERROR == err)
        {
            // 当返回值为 QS_ERR_NO_ERROR 时,代表得到了符合预期的 response ,可以使用 output 中的信息完成你需要的业务逻辑
            std::vector<KeyType> keys = output.GetKeys();
            printf("Got %d objects\n" ,keys.size());
        }
    
        if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            ResponseErrorInfo  errorInfo = output.GetResponseErrInfo();
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }
  6. 删除一个 Object

        DeleteObjectInput input;
        DeleteObjectOutput output;
    
        QsError err = qsBucket.DeleteObject(objectkey, input, output);
        if (QsError::QS_ERR_NO_ERROR == err)
        {
            // 当返回值为 QS_ERR_NO_ERROR 时,代表得到了符合预期的 response ,可以使用 output 中的信息完成你需要的业务逻辑
            printf("Got response code : %s",output.GetResponseCode());
        }
    
        if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            ResponseErrorInfo  errorInfo = output.GetResponseErrInfo();
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }
  7. 查看一个 Object 的状态

        HeadObjectInput input;
        HeadObjectOutput output;
    
        QsError err = qsBucket.HeadObject(objectkey, input, output);
        if (QS_ERR_NO_ERROR == err)
        {
            // 当返回值为 QS_ERR_NO_ERROR 时,代表得到了符合预期的 response ,可以使用 output 中的信息完成你需要的业务逻辑
            printf("Got response code : %s",output.GetResponseCode());
        }
    
        if (QS_ERR_UNEXCEPTED_RESPONSE == err)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            ResponseErrorInfo  errorInfo = output.GetResponseErrInfo();
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }
  8. 初始化一个分段上传

        initiateMultipartUpload input;
        initiateMultipartUpload output;
    
        QsError err = qsBucket.InitiateMultipartUpload(objectkey, input, output);
        if (QsError::QS_ERR_NO_ERROR == err)
        {
            // 当返回值为 QS_ERR_NO_ERROR 时,代表得到了符合预期的 response ,可以使用 output 中的信息完成你需要的业务逻辑
            printf("Got response code : %s",output.GetResponseCode());
    
            // 获取 Upload ID , 假设此处为 "9d37dd6ccee643075ca4e597ad65655c"
            printf("The upload id is : %s",output.GetUploadID());
        }
    
        if (QS_ERR_UNEXCEPTED_RESPONSE == err)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }
  9. 上传一个分段

        // 上传第1个分段
        UploadMultipartInput inputPart1;
        UploadMultipartOutput outputPart1;
    
        // object 的内容可以是任何形式的 stream,只需要保证其为 iostream 的子类, 分段最小为 4MB,每个分段最大为 5GB
        std::iostream* objectStream1 = new std::fstream(filePath1));
        objectStream1->seekg(0, objectStream1->end);
        size_t streamSize1 = objectStream1->tellg();
        objectStream1->seekg(0, objectStream1->beg);
        inputPart1.SetBody(objectStream1);
        inputPart1.SetContentLength(streamSize1);
        inputPart1.SetPartNumber(1);
        inputPart1.SetUploadID("9d37dd6ccee643075ca4e597ad65655c");
        QsError err1 = qsBucket.UploadMultipart(objectkey, inputPart1, outputPart1);
        if (QsError::QS_ERR_NO_ERROR == err1)
        {
            // 当返回值为 QS_ERR_NO_ERROR 时,代表得到了符合预期的 response ,可以使用 output 中的信息完成你需要的业务逻辑
            printf("Got response code : %s",output.GetResponseCode());
        }
    
        if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err1)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }
    
        // 释放资源
        if(objectStream1)
            delete objectStream1;
    
        // 上传第2个分段
        UploadMultipartInput inputPart2;
        UploadMultipartOutput outputPart2;
    
        // object 的内容可以是任何形式的 stream,只需要保证其为 iostream 的子类, 分段最小为 4MB,每个分段最大为 5GB
        std::iostream* objectStream2 = new std::fstream(filePath2));
        objectStream2->seekg(0, objectStream2->end);
        size_t streamSize2 = objectStream2->tellg();
        objectStream2->seekg(0, objectStream2->beg);
        inputPart2.SetBody(objectStream2);
        inputPart2.SetContentLength(streamSize2);
        inputPart2.SetPartNumber(2);
        inputPart2.SetUploadID("9d37dd6ccee643075ca4e597ad65655c");
    
        QsError err2 = qsBucket.UploadMultipart(objectkey, inputPart2, outputPart2);
        if (QsError::QS_ERR_NO_ERROR == err2)
        {
            // 当返回值为 QS_ERR_NO_ERROR 时,代表得到了符合预期的 response ,可以使用 output 中的信息完成你需要的业务逻辑
            printf("Got response code : %s",output.GetResponseCode());
        }
    
        if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err2)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }
    
        // 释放资源
        if(objectStream2)
            delete objectStream2;
  10. 列出已经上传的分段

        ListMultipartInput input;
        ListMultipartOutput output;
    
        input.SetUploadID("9d37dd6ccee643075ca4e597ad65655c");
        std::vector < ObjectPartType > objectParts;
    
        QsError err = qsBucket.ListMultipart (objectkey, input, output);
        if (QS_ERR_NO_ERROR == err)
        {
            objectParts = output.GetObjectParts();
            printf(Got "%d object parts\n",objectParts.size());
        }
    
        if (QS_ERR_UNEXCEPTED_RESPONSE == err)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }
  11. 完成一个分段上传

        CompleteMultipartUploadInput input;
        CompleteMultipartUploadOutput output;
    
        // 设置确认完成合并的 part 列表
        std::vector<ObjectPartType> objectParts;
        ObjectPartType part1,part2;
        part1.SetPartNumber(1);
        part2.SetPartNumber(2);
        objectParts.push_back(part1);
        objectParts.push_back(part2);
    
        input.SetUploadID ("9d37dd6ccee643075ca4e597ad65655c");
        input.SetObjectParts(objectParts);
    
        QsError err = qsBucket.CompleteMultipartUpload (objectkey, input, output);
        if (QS_ERR_NO_ERROR == err)
        {
            // 当返回值为 QS_ERR_NO_ERROR 时,代表得到了符合预期的 response ,可以使用 output 中的信息完成你需要的业务逻辑
            printf("Got response code : %s",output.GetResponseCode());
        }
    
        if (QS_ERR_UNEXCEPTED_RESPONSE == err)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }
  12. 取消一个分段上传

        AbortMultipartUploadInput input;
        AbortMultipartUploadOutput output;
    
        // 设置要取消的 Upload ID,对应的所有已上传分段会被删除
        input.SetUploadID("9d37dd6ccee643075ca4e597ad65655c");
    
        QsError err = qsBucket.abortMultipartUpload(objectkey, input, output);
        if (QS_ERR_NO_ERROR == err)
        {
            // 当返回值为 QS_ERR_NO_ERROR 时,代表得到了符合预期的 response ,可以使用 output 中的信息完成你需要的业务逻辑
            printf("Got response code : %s",output.GetResponseCode());
        }
    
        if (QS_ERR_UNEXCEPTED_RESPONSE == err)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }
  13. 获取存储空间访问控制

    QingStor 对象存储支持 Bucket ACL,是 Bucket 级别的访问权限控制。用户可将 Bucket 的读、写、或读写权限开放给单个或多个青云 QingCloud 用户。下面我们将演示如何通过 API 接口来获取和设置 Bucket ACL。

        GetBucketACLInput input;
        GetBucketACLOutput output;
    
        QsError err = qsBucket.GetBucketACL(input, output);
        if (QS_ERR_NO_ERROR == err)
        {
            // 当返回值为 QS_ERR_NO_ERROR 时,代表得到了符合预期的 response ,可以使用 output 中的信息完成你需要的业务逻辑
            if (contextOutput->GetACL().size())
            {
                std::string granteeName = contextOutput->GetACL().at(1).GetGrantee().GetName();
                printf("The first ACL Grantee Name is : %s",granteeName.c_str());
            }
        }
    
        if (QS_ERR_UNEXCEPTED_RESPONSE == err)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }
  14. 设置存储空间访问控制

        PutBucketACLInput input;
        PutBucketACLOutput output;
    
        // 设置 ACL 列表
        std::vector<ACLType> aclList;
        ACLType acl;
        GranteeType grantee;
        grantee.SetType("group");
        grantee.SetName("QS_ALL_USERS");
        acl.SetGrantee(grantee);
        acl.SetPermission("FULL_CONTROL");
        aclList.push_back(acl);
        input.SetACL(aclList);
    
        QsError err = qsBucket.PutBucketACL(input, output);
        if (QS_ERR_NO_ERROR == err)
        {
            // 当返回值为 QS_ERR_NO_ERROR 时,代表得到了符合预期的 response ,可以使用 output 中的信息完成你需要的业务逻辑
            printf("Got response code : %s",output.GetResponseCode());
        }
    
        if (QS_ERR_UNEXCEPTED_RESPONSE == err)
        {
            // 当返回值为 QS_ERR_UNEXCEPTED_RESPONSE 时,代表得到了不符合预期的 response,可以进一步判定错误描述细节
            printf("request_id = %s , %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str());
        }

更多操作

所有的 API 调用接口均与上面的示例相似,用户可以查看 QingStor 对象存储API 文档来了解更多信息。