分块上传

最近更新时间: 2024-10-17 17:10:00

适用场景

分块上传适合于在弱网络或高带宽环境下上传较大的对象。COS 的控制台和 SDK 会协助您将单个对象切成一组分块并完成上传,您也可以自行切分对象并分别调用 API 上传各个分块。使用分块上传有一些优势:

  • 在弱网络环境中,使用较小的分块可以将网络失败导致的中断影响降低,实现对象续传。

  • 在高带宽环境中,并发上传对象分块能充分利用网络带宽,乱序上传并不影响最终组合对象。

  • 使用分块上传,您可以随时暂停和恢复单个大对象的上传。除非发起终止操作,所有未完成的对象将可随时继续上传。

  • 分块上传也适用于在未知对象总大小的情况下上传对象,您可以先发起上传,再组合对象以获得完整大小。

上传时,这组分块将会按连续的序号编号,您可以独立上传或者按照任意顺序上传各个分块,最终 COS 将会根据分块编号顺序重新组合出该对象。任意分块传输失败,都可以重新传输当前分块,不会影响其他分块和内容完整性。一般在弱网络环境中,当单个对象大于 20 MB 可优先考虑分块上传,在大带宽环境中可将超过 100 MB 的对象进行分块上传。

使用方法

使用 REST API

您可以直接使用 REST API 发起一个分块上传的请求,可参考以下 API 文档部分:

  • Initiate Multipart Upload

  • Complete Multipart Upload

  • Upload Part

  • Abort Multipart Upload

使用 Java SDK

对象存储 COS 的 Java SDK 中提供了此方法,可参考 Java SDK 接口文档 PUT object 中的分块文件上传部分。

步骤说明

  1. 初始化客户端 cosclient。

  2. 使用 initiateMultipartUpload 初始化分块上传获取一个新的 uploadid,或者调用 listMultipartUploads 获取之前还未完成的分块上传,得到 uploadid。

  3. 已上传的分块可使用 listParts 进行获取,未上传的分块使用 uploadPart 上传分块数据, 或者 copyPart 选择从另外一个文件 copy 分块到目前文件。以此达到断点续传的功能,如果对已上传的分块再次调用 uploadPart 或者 copyPart 则会覆盖已上传的分块数据。

  4. 使用 completeMultipartUpload 完成分块上传或者调用 abortMultipartUpload 终止分块上传。

代码示例

  1. InitiateMultipartUploadRequest是初始化分块上传的请求,包含了分快上传的路径,存储类型等信息。通过调用 initiateMultipartUpload 可获得一个新的分快上传 ID。
// 1 初始化用户身份信息(secretId, secretKey)    
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");  
// 2 设置bucket的区域, COS地域的简称请参照 /document/product/436/6224     
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端    
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";

String key = "aaa/bbb.txt";
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, key);
// 设置存储类型, 默认是标准(Standard), 低频(standard_ia), 近线(nearline)   
request.setStorageClass(StorageClass.Standard_IA);
try {
    InitiateMultipartUploadResult initResult = cosclient.initiateMultipartUpload(request);
    // 获取uploadid
    String uploadId =  initResult.getUploadId();
} catch (CosServiceException e) {
    e.printStackTrace();
} catch (CosClientException e) {
    e.printStackTrace();
}

cosclient.shutdown();
  1. UploadPartRequest是分块上传请求,包含了要上传的数据,分块号。通过调用uploadPart 上传分块,并获取分块的 partEtag。
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 /document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
String key = "aaa/bbb.txt";
// uploadid(通过initiateMultipartUpload或者ListMultipartUploads获取)
String uploadId = "1512380198aecfed004aeaaca195d08232f718f7b52a91b8f6e9d36c7dfead2b3d1c917a6f";

// 生成要上传的数据, 这里初始化一个1M的数据
byte data[] = new byte[1024 * 1024];
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setKey(key);
uploadPartRequest.setUploadId(uploadId);
// 设置分块的数据来源输入流
uploadPartRequest.setInputStream(new ByteArrayInputStream(data));
// 设置分块的长度
uploadPartRequest.setPartSize(data.length); // 设置数据长度
uploadPartRequest.setPartNumber(10);     // 假设要上传的part编号是10

try {
    UploadPartResult uploadPartResult = cosclient.uploadPart(uploadPartRequest);
    PartETag partETag = uploadPartResult.getPartETag();
} catch (CosServiceException e) {
    e.printStackTrace();
} catch (CosClientException e) {
    e.printStackTrace();
}

cosclient.shutdown();
  1. CompleteMultipartUploadRequest是完成分块请求,需要传入之前上传的所有分块的partEtag。通过调用completeMultipartUpload完成分块上传。示例代码如下:
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 /document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
String key = "aaa/bbb.txt";
// uploadid(通过initiateMultipartUpload或者ListMultipartUploads获取)
String uploadId = "1512380198aecfed004aeaaca195d08232f718f7b52a91b8f6e9d36c7dfead2b3d1c917a6f";

// 这里初始化一个空的队列, 用于保存已上传的分片信息, 代码不能直接运行, 需要通过之前的uploadpart或者list parts的结果获取,加入到partEtags队列中 
List<PartETag> partETags = new LinkedList<>();

// 分片上传结束后,调用complete完成分片上传
CompleteMultipartUploadRequest completeMultipartUploadRequest =
        new CompleteMultipartUploadRequest(bucketName, key, uploadId, partETags);
try {
    CompleteMultipartUploadResult completeResult =
            cosclient.completeMultipartUpload(completeMultipartUploadRequest);
    String etag = completeResult.getETag();
} catch (CosServiceException e) {
    e.printStackTrace();
} catch (CosClientException e) {
    e.printStackTrace();
}

cosclient.shutdown();
  1. AbortMultipartUploadRequest是终止分块上传请求,用于终止一个未 complete 的分块上传,表示中断销毁之前已上传的分块。通过调用 abortMultipartUpload 终止分块上传请求,示例代码如下:
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 /document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
String key = "aaa/bbb.txt";
// uploadid(通过initiateMultipartUpload或者ListMultipartUploads获取)
String uploadId = "1512380198aecfed004aeaaca195d08232f718f7b52a91b8f6e9d36c7dfead2b3d1c917a6f";

AbortMultipartUploadRequest abortMultipartUploadRequest = new AbortMultipartUploadRequest(bucketName, key, uploadId);
try {
    cosclient.abortMultipartUpload(abortMultipartUploadRequest);
} catch (CosServiceException e) {
    e.printStackTrace();
} catch (CosClientException e) {
    e.printStackTrace();
}

cosclient.shutdown();
  1. ListPartsRequest是列出已上传的分块的请求,可用于断点续传。通过调用 listParts 获取已上传的分块,示例代码如下:
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 /document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);

// bucket名需包含appid
String bucketName = "mybucket-1251668577";
String key = "aaa/bbb.txt";
// uploadid(通过initiateMultipartUpload或者ListMultipartUploads获取)
String uploadId = "1512380198aecfed004aeaaca195d08232f718f7b52a91b8f6e9d36c7dfead2b3d1c917a6f";

List<PartETag> partETags = new LinkedList<>();      // 用于保存已上传的分片信息
PartListing partListing = null;
ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, key, uploadId);
do {
    try {
        partListing = cosclient.listParts(listPartsRequest);
    } catch (CosServiceException e) {
        e.printStackTrace();
    } catch (CosClientException e) {
        e.printStackTrace();
    }
    for (PartSummary partSummary : partListing.getParts()) {
        partETags.add(new PartETag(partSummary.getPartNumber(), partSummary.getETag()));
    }
    listPartsRequest.setPartNumberMarker(partListing.getNextPartNumberMarker());
} while (partListing.isTruncated());

cosclient.shutdown();
  1. CopyPartResult是分块 copy 的请求,表示该分块的数据来源于另外一个文件的某一部分。通过要拷贝的源文件的路径,bucket 信息,字节范围。调用 copyPart 可实现分块copy。示例代码如下所示:
// 1 初始化用户身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials("AKIDXXXXXXXX", "1A2Z3YYYYYYYYYY");
// 2 设置bucket的区域, COS地域的简称请参照 /document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1"));
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid
String bucketName = "mybucket-1251668577";
String key = "aaa/bbb.txt";
// uploadid(通过initiateMultipartUpload或者ListMultipartUploads获取)
String uploadId = "1512380198aecfed004aeaaca195d08232f718f7b52a91b8f6e9d36c7dfead2b3d1c917a6f";

CopyPartRequest copyPartRequest = new CopyPartRequest();
// 要拷贝的源文件所在的region
copyPartRequest.setSourceBucketRegion(new Region("ap-beijing-1"));
// 要拷贝的源文件的bucket名称
copyPartRequest.setSourceBucketName(bucketName);
// 要拷贝的源文件的路径
copyPartRequest.setSourceKey("aaa/ccc.txt");
// 指定要拷贝的源文件的数据范围(类似content-range)
copyPartRequest.setFirstByte(0L);
copyPartRequest.setLastByte(1048575L);
// 目的bucket名称
copyPartRequest.setDestinationBucketName(bucketName);
// 目的路径名称
copyPartRequest.setDestinationKey(key);

// uploadid
copyPartRequest.setUploadId(uploadId);
try {
    CopyPartResult copyPartResult = cosclient.copyPart(copyPartRequest);
    PartETag partETag = copyPartResult.getPartETag();
} catch (CosServiceException e) {
    e.printStackTrace();
} catch (CosClientException e) {
    e.printStackTrace();
}

cosclient.shutdown();