列举已上传的片段

分段上传可以将大文件分割成片段后上传,除了最后一个片段,每个片段的数据大小为5MB~5GB。本文介绍如何列举已上传的片段部分。

接口定义:

void S3_list_parts(S3BucketContext *bucketContext, const char *key,
                   const char *partnumbermarker,
                   const char *uploadid, const char *encodingtype,
                   int maxparts, S3RequestContext *requestContext,
                   int timeoutMs,
                   const S3ListPartsHandler *handler, void *callbackData);

参数:

参数名 类型 说明
bucketContext S3BucketContext * 包含bucket及相关的请求参数
key const char * 将要上传的对象的文件名
partnumbermarker const char * 如果非NULL,则仅列出partnumber比该参数高的part
upload_id const char * S3_initiate_multipart中得到的upload_id
encodingtype const char * 如果非NULL,则请求服务器以指定方法编码响应
maxparts int 指定返回响应体中part的最大数量
requestContext S3RequestContext * 请求参数,如果为NULL,则立即同步执行请求
timeoutMs int 如果非0,则是以毫秒为单位的请求超时时间
handler const S3ListPartsHandler * 回调函数
callbackData void * 回调数据

示例代码:

typedef struct growbuffer
{
    // The total number of bytes, and the start byte
    int size;
    // The start byte
    int start;
    // The blocks
    char data[64 * 1024];
    struct growbuffer *prev, *next;
} growbuffer;

typedef struct UploadManager
{
    //used for initial multipart
    char *upload_id;

    //used for upload part object
    char **etags;
    int next_etags_pos;

    //used for commit Upload
    growbuffer *gb;
    int remaining;
} UploadManager;

typedef struct list_parts_callback_data
{
    int isTruncated;
    char nextPartNumberMarker[24];
    char initiatorId[256];
    char initiatorDisplayName[256];
    char ownerId[256];
    char ownerDisplayName[256];
    char storageClass[256];
    int partsCount;
    int handlePartsStart;
    int allDetails;
    int noPrint;
    UploadManager *manager;
} list_parts_callback_data;

void printListMultipartHeader(int allDetails)
{
    (void)allDetails;
}

void printListPartsHeader()
{
    printf("%-25s  %-30s  %-30s   %-15s",
           "LastModified",
           "PartNumber", "ETag", "SIZE");

    printf("\n");
    printf("---------------------  "
           "    -------------    "
           "-------------------------------  "
           "               -----");
    printf("\n");
}

S3Status listPartsCallback(int isTruncated,
                                  const char *nextPartNumberMarker,
                                  const char *initiatorId,
                                  const char *initiatorDisplayName,
                                  const char *ownerId,
                                  const char *ownerDisplayName,
                                  const char *storageClass,
                                  int partsCount,
                                  int handlePartsStart,
                                  const S3ListPart *parts,
                                  void *callbackData)
{
    list_parts_callback_data *data =
        (list_parts_callback_data *)callbackData;

    data->isTruncated = isTruncated;
    data->handlePartsStart = handlePartsStart;
    UploadManager *manager = data->manager;

    if (nextPartNumberMarker)
    {
        snprintf(data->nextPartNumberMarker,
                 sizeof(data->nextPartNumberMarker), "%s",
                 nextPartNumberMarker);
    }
    else
    {
        data->nextPartNumberMarker[0] = 0;
    }

    if (initiatorId)
    {
        snprintf(data->initiatorId, sizeof(data->initiatorId), "%s",
                 initiatorId);
    }
    else
    {
        data->initiatorId[0] = 0;
    }

    if (initiatorDisplayName)
    {
        snprintf(data->initiatorDisplayName,
                 sizeof(data->initiatorDisplayName), "%s",
                 initiatorDisplayName);
    }
    else
    {
        data->initiatorDisplayName[0] = 0;
    }

    if (ownerId)
    {
        snprintf(data->ownerId, sizeof(data->ownerId), "%s",
                 ownerId);
    }
    else
    {
        data->ownerId[0] = 0;
    }

    if (ownerDisplayName)
    {
        snprintf(data->ownerDisplayName, sizeof(data->ownerDisplayName), "%s",
                 ownerDisplayName);
    }
    else
    {
        data->ownerDisplayName[0] = 0;
    }

    if (storageClass)
    {
        snprintf(data->storageClass, sizeof(data->storageClass), "%s",
                 storageClass);
    }
    else
    {
        data->storageClass[0] = 0;
    }

    if (partsCount && !data->partsCount && !data->noPrint)
    {
        printListPartsHeader();
    }

    int i;
    for (i = 0; i < partsCount; i++)
    {
        const S3ListPart *part = &(parts[i]);
        char timebuf[256];
        if (data->noPrint)
        {
            manager->etags[handlePartsStart + i] = strdup(part->eTag);
            manager->next_etags_pos++;
            manager->remaining = manager->remaining - part->size;
        }
        else
        {
            time_t t = (time_t)part->lastModified;
            strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ",
                     gmtime(&t));
            printf("%-30s", timebuf);
            printf("%-15llu", (unsigned long long)part->partNumber);
            printf("%-45s", part->eTag);
            printf("%-15llu\n", (unsigned long long)part->size);
        }
    }

    data->partsCount += partsCount;

    return S3StatusOK;
}

void list_parts(const char *key,
                       const char *uploadid, const char *partnumbermarker,
                       const char *encodingtype, int maxparts)
{
    int allDetails = 1;

    S3ListPartsHandler listPartsHandler =
        {
            {&responsePropertiesCallback, &responseCompleteCallback},
            &listPartsCallback};

    list_parts_callback_data data;

    memset(&data, 0, sizeof(list_parts_callback_data));
    if (partnumbermarker != 0)
    {
        snprintf(data.nextPartNumberMarker,
                 sizeof(data.nextPartNumberMarker), "%s", partnumbermarker);
    }

    data.partsCount = 0;
    data.allDetails = allDetails;
    data.noPrint = 0;

    do
    {
        data.isTruncated = 0;
        do
        {
            S3_list_parts(&bucketContext, key, data.nextPartNumberMarker,
                          uploadid, encodingtype,
                          maxparts,
                          0, 0,
                          &listPartsHandler, &data);
        } while (S3_status_is_retryable(statusG) && should_retry());
        if (statusG != S3StatusOK)
        {
            break;
        }
    } while (data.isTruncated &&
             (!maxparts || (data.partsCount < maxparts)));

    if (statusG == S3StatusOK)
    {
        if (!data.partsCount)
        {
            printListMultipartHeader(data.allDetails);
        }
    }
    else
    {
        printError();
    }
}