You need to enable JavaScript to run this app.
导航

分片上传(C++ SDK)

最近更新时间2024.03.21 15:13:15

首次发布时间2022.04.08 10:56:30

对于较大的对象,可以分成多个数据块(part)来分别上传,最后调用合并分片将上传的数据块合并为一个对象。

注意事项

  • 分片上传前,您必须具有 tos:PutObject 权限,具体操作,请参见权限配置指南
  • 取消分片上传任务前,您必须具有 tos:AbortMultipartUpload 权限,具体操作,请参见权限配置指南
  • 分片编号从 1 开始,最大为 10000。除最后一个分片以外,其他分片大小最小为 4MiB。
  • 上传对象时,对象名必须满足一定规范,详细信息,请参见对象命名规范
  • TOS 是面向海量存储设计的分布式对象存储产品,内部分区存储了对象索引数据,为横向扩展您上传对象和下载对象时的最大吞吐量,和减小热点分区的概率,请您避免使用字典序递增的对象命名方式,详细信息,请参见性能优化
  • 如果桶中已经存在同名对象,则新对象会覆盖已有的对象。如果您的桶开启了版本控制,则会保留原有对象,并生成一个新版本号用于标识新上传的对象。

分片上传步骤

分片上传一般包含以下三个步骤:

  1. 初始化分片上传任务。
    在上传分片数据之前,需要先通过 createMultipartUpload 接口初始化并获取一个分片任务的uploadID,后续的上传分片、合并分片、取消分片和列举已上传分片都需要传入 uploadID 参数。初始化分片上传任务不影响已存在的同名对象。
  2. 上传分片。
    通过此接口上传分片数据,且需要指定通过 createMultipartUpload 获取的 uploadID,以及分片的编号,编号的范围是[1, 10000]。同一个对象的同一个分片任务,支持多个分片同时上传,上传顺序不影响最终的合并分片操作。
    SDK 支持通过 uploadPart 进行直接分片上传,也支持 uploadPartFromFile 通过文件进行分片上传。

    说明

    • 对于同一个分片上传任务(通过 uploadId 标识),分片编号(partNumber)标识了该分片在整个对象中的相对位置。若通过同一分片编号上多次上传数据,TOS 中会覆盖原始数据,并以最后一次上传数据为准。
    • 响应头中包含了数据的 MD5 值,可通过 ETag 获取。合并分片时,您需指定当前分片上传任务中的所有分片信息(分片编号、ETag 值)。
  3. 完成分片上传。
    所有分片上传完成后,调用 completeMultipartUpload 方法将所有分片合并成一个完整的对象。

示例代码

分片上传完整过程

以下代码通过分片上传将本地文件上传到目标桶 examplebucket 中的 exampledir/exampleobject.txt 对象。并在上传时指定 ACL 为 PublicRead、存储类型为低频存储以及添加自定义元数据。

#include "TosClientV2.h"
using namespace VolcengineTos;

static int64_t getFileSize(const std::string& file)
{
    std::fstream f(file, std::ios::in | std::ios::binary);
    f.seekg(0, f.end);
    int64_t size = f.tellg();
    f.close();
    return size;
}

int main(void){
    // 初始化 TOS 账号信息
    // Your Region 填写 Bucket 所在 Region
    std::string region = "Your Region";
    std::string accessKey = std::getenv("TOS_ACCESS_KEY");
    std::string secretKey = std::getenv("TOS_SECRET_KEY");
    // 填写 Bucket 名称,例如 examplebucket
    std::string bucketName = "examplebucket";
    // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
    std::string objectName = "exampledir/exampleobject.txt";

     // 初始化网络等资源
    InitializeClient();
    // 创建交互的 client
    TosClientV2 client(region, accessKey, secretKey);
    // 初始化分片上传事件
    CreateMultipartUploadInput input(bucketName, objectName);
    // 可以指定 ACL,StorageClass,用户自定义元数据等
    input.setAcl(ACLType::PublicRead);
    input.setStorageClass(StorageClassType::IA);
    input.setMeta({{"self-test", "yes"}});
    auto upload = client.createMultipartUpload(input);
    if (!upload.isSuccess()) {
        // 异常处理
        std::cout << "createMultipartUpload failed." << upload.error().String() << std::endl;
        // 释放网络等资源
        CloseClient();
        return -1;
    }
    std::cout << "createMultipartUpload success." << std::endl;

    // 准备上传的文件
    std::string fileToUpload = "yourLocalFilename";
    // 5MB
      int64_t partSize = 5 * 1024 * 1024;
    std::vector<UploadedPartV2> partResList;
    auto fileSize = getFileSize(fileToUpload);
    int partCount = static_cast<int>(fileSize / partSize);
    // 计算分片个数
    if (fileSize % partSize != 0) {
        partCount++;
    }

    // 对每一个分片进行上传
    auto uploadId = upload.result().getUploadId();
    for (int i = 1; i <= partCount; i++) {
        auto offset = partSize * (i - 1);
        auto size = (partSize < fileSize - offset) ? partSize : (fileSize - offset);
        std::shared_ptr<std::iostream> content = std::make_shared<std::fstream>(fileToUpload, std::ios::in|std::ios::binary);
        content->seekg(offset, std::ios::beg);

        UploadPartV2Input uploadPartInput(bucketName, objectName,uploadId, size,i,content);
        auto uploadPartOutput = client.uploadPart(uploadPartInput);
        if (!uploadPartOutput.isSuccess()) {
            std::cout << "uploadPart failed." << upload.error().String() << std::endl;
            // 释放网络等资源
                CloseClient();
            return -1;
        }

        UploadedPartV2 part(i, uploadPartOutput.result().getETag());
        partResList.push_back(part);
    }

    // 完成分片上传
    CompleteMultipartUploadV2Input completeMultipartUploadInput(bucketName, objectName, uploadId, partResList);
    auto com = client.completeMultipartUpload(completeMultipartUploadInput);
    if (!com.isSuccess()) {
        // 异常处理
        std::cout << "CompleteMultipartUpload failed." << upload.error().String() << std::endl;
        // 释放网络等资源
        CloseClient();
        return -1;
    }
    std::cout << "CompleteMultipartUpload success." << com.result().getRequestInfo().getRequestId() << std::endl;
    // 释放网络等资源
    CloseClient();
    return 0;
}

列举已上传的分片信息

以下代码用于列举桶 examplebucket 中对象 exampledir/exampleobject.txt 已上传的分片信息。

#include "TosClientV2.h"
using namespace VolcengineTos;

int main(void){
    // 初始化 TOS 账号信息
    // Your Region 填写 Bucket 所在 Region。
    std::string region = "Your Region";
    std::string accessKey = std::getenv("TOS_ACCESS_KEY");
    std::string secretKey = std::getenv("TOS_SECRET_KEY");
    // 填写 Bucket 名称,例如 examplebucket。
    std::string bucketName = "examplebucket";
    // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
    std::string objectName = "exampledir/exampleobject.txt";
    // 填写UploadId,例如 f93f6fc9da94371f321e1008。uploadId来自于CreateMultipartUploadInput返回的结果。
    std::string uploadId = "f93f6fc9da94371f321e1008";
    
    
    // 初始化网络等资源
    InitializeClient();
    // 创建交互的 client
    TosClientV2 client(region, accessKey, secretKey);

    // 列举已上传分片,默认列举1000个分片
    ListPartsInput input(bucketName,objectName,uploadId);
    // 设置返回分片上传任务的最大数量。
    input.setMaxParts(100);
    // 指定分片号的起始位置,只列举分片号大于此值的段,以 1 为例子。
    input.setPartNumberMarker(1);
    auto output = client.listParts(input);
    if (!output.isSuccess()) {
        // 异常处理
        std::cout << "ListParts failed." << output.error().String() << std::endl;
        // 释放网络等资源
        CloseClient();
        return -1;
    }
    std::cout << "ListParts success." << std::endl;
    for (const auto& part : output.result().getParts()) {
        std::cout << "part"<<
                ",partNumber:" << part.getPartNumber() <<
                ",eTag:" << part.getETag() <<
                ",size:" << part.getSize() <<
                ",lastModified time:" << part.getStringFormatLastModified() << std::endl;
    }
    // 释放网络等资源
    CloseClient();
    return 0;
}

取消分片上传任务

您可以通过 abortMultipartUpload 方法来取消分片上传任务。当一个分片任务被取消后, TOS 会将已上传的分片数据删除,同时您无法再对此分片任务进行任何操作。
以下代码用于取消桶 examplebucket 中对象 exampledir/exampleobject.txt 的分片上传任务。

#include "TosClientV2.h"
using namespace VolcengineTos;

int main(void){
int UploadObjectSample::AbortMultipartUpload(){
    // 初始化 TOS 账号信息
    // Your Region 填写 Bucket 所在 Region。
    std::string region = "Your Region";
    std::string accessKey = std::getenv("TOS_ACCESS_KEY");
    std::string secretKey = std::getenv("TOS_SECRET_KEY");
    // 填写 Bucket 名称,例如 examplebucket。
    std::string bucketName = "examplebucket";
    // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
    std::string objectName = "exampledir/exampleobject.txt";
    // 填写UploadId,例如 f93f6fc9da94371f321e1008。uploadId来自于CreateMultipartUploadInput返回的结果。
    std::string uploadId = "f93f6fc9da94371f321e1008";


    // 初始化网络等资源
    InitializeClient();
    // 创建交互的 client
    TosClientV2 client(region, accessKey, secretKey);

    // 列举已上传分片,默认列举1000个分片
    AbortMultipartUploadInput input(bucketName,objectName,uploadId);
    auto output = client.abortMultipartUpload(input);
    if (!output.isSuccess()) {
        // 异常处理
        std::cout << "AbortMultipartUpload failed." << output.error().String() << std::endl;
        // 释放网络等资源
        CloseClient();
        return -1;
    }
    std::cout << "AbortMultipartUpload success." << std::endl;
    // 释放网络等资源
    CloseClient();
    return 0;
}

相关文档