Object的分块上传
除了通过putObject接口上传文件到OSS以外,OSS还提供了另外一种上传模式 —— Multipart Upload。用户可以在如下的应用场景内(但不仅限于此),使用Multipart Upload上传模式,如:
- 需要支持断点上传。
- 上传超过100MB大小的文件。
- 网络条件较差,和OSS的服务器之间的链接经常断开。
- 需要流式地上传文件。
- 上传文件之前,无法确定上传文件的大小。
下面我们将一步步介绍怎样实现Multipart Upload。
分步完成Multipart Upload
假设我们有一个文件,本地路径为 /path/to/file.zip 由于文件比较大,我们将其分块传输到OSS中。
1. 初始化Multipart Upload
<?php $initResult = $client->initiateMultipartUpload(array( 'Bucket' => 'your-bucket-name', 'Key' => 'your-object-key', )); echo $initResult->getUploadId();
initiateMultipartUpload 方法用来初始化一个分块上传事件,它会返回一个uploadId作为事件标识。在后面的步骤里,我们可以使用uploadId分块将文件上传上去。
2. 上传分块
<?php $uploadFile = '/path/to/file.zip'; $filesize = filesize($uploadFile); $partSize = 1024 * 1024 * 5; //5M $partETags = array(); //Used for complete multipart // Decide how many parts should be uploaded. $partNumber = floor($filesize / $partSize); if ($filesize % $partSize > 0) { $partNumber += 1; } for ($i = 1; $i <= $partNumber; $i++) { $upSize = $partSize; // The last part if ($i == $partNumber) { $upSize = $filesize - ($partNumber - 1) * $partSize; } $content = fopen($uploadFile, 'r'); fseek($content, ($i - 1) * $partSize); $uploadResult = $client->uploadPart(array( 'Bucket' => 'your-bucket-name', 'Key' => 'your-object-key', 'UploadId' => $initResult->getUploadId(), 'Content' => $content, 'PartNumber' => $i, 'PartSize' => $upSize, )); $partETags[] = $uploadResult->getPartETag(); }
uploadPart 方法需要传入以下几个参数:
- Bucket: Object所在的Bucket的名字
- Key: Oject的Key
- UploadId: 在初始化上传阶段得到的上传Id。
- Content: 本次上传的内容。对于分块上传来讲,如果Content为resource类型,则需要在上传之前把其定位到本次上传块的开始位置。
- PartNumber: 上传的序号,用来标识不同上传块。
- PartSize: 本次上传块的大小,最小为5M。
在每次上传的返回结果中我们都会得到上传返回的PartETag,它是ParNumber和上传块ETag的组合。在上面的代码中,我们将其以此放入数组中,以便在完成分块上传时使用。
3. 完成分块上传
<?php $client->completeMultipartUpload(array( 'Bucket' => 'your-bucket-name', 'Key' => 'your-object-key', 'UploadId' => $initResult->getUploadId(), 'PartETags' => $partETags, ));
上面代码中的 $partETags 就是第二部中保存的partETag的列表,OSS收到用户提交的Part列表后,会逐一验证每个数据Part的有效性。当所有的数据Part验证通过后,OSS将把这些数据part组合成一个完整的Object。
取消分块上传事件
我们可以用 abortMultipartUpload 方法取消分块上传。
<?php $client->abortMultipartUpload(array( 'Bucket' => 'your-bucket-name', 'Key' => 'your-object-key', 'UploadId' => $initResult->getUploadId(), ));
获取Bucket内所有分块上传事件
我们可以用 listMultipartUploads 方法获取Bucket内所有上传事件。
<?php $listMultipartUploadsResult = $client->listMultipartUploads(array( 'Bucket' => 'your-bucket-name', )); foreach ($listMultipartUploadsResult->getMultipartUploads() as $multipartUpload) { echo 'Bucket: ' . $listMultipartUploadsResult->getBucketName() . ' Key: ' . $multipartUpload->getKey() . ' UploadId: ' . $multipartUpload->getUploadId(); echo "\n"; }
Note
默认情况下,如果Bucket中的分块上传事件的数量大于1000,则只会返回1000个事件, 且返回结果中 IsTruncated 为 false,并返回 NextKeyMarker 和 NextUploadMarker 作为下次读取的起点。若想增大返回分块上传事件数目,可以修改 MaxUploads 参数,或者使用 KeyMarker 以及 UploadIdMarker 参数分次读取。
获取所有已上传的块信息
我们可以用 listParts 方法获取某个上传事件所有已上传的块。
<?php $listPartsResult = $client->listParts(array( 'Bucket' => 'your-bucket-name', 'Key' => 'your-object-key', 'UploadId' => $initResult->getUploadId(), )); foreach ($listPartsResult->getParts() as $part) { echo $part->getPartNumber() . "\n"; }
Note
默认情况下,如果上传块的数量大于1000,则只会返回1000个Object, 且返回结果中 IsTruncated 为 false,并返回 NextPartNumberMarker 作为下次读取的起点。若想增大返回块的数目,可以修改 MaxParts 参数,或者使用 PartNumberMarker 参数分次读取。