标准接口

简单上传方式只能上传小于5GB的对象,如果需要上传超过5GB的对象,您必须使用分片上传模式。此外,您也可以在如下的应用场景内(但不仅限于此),使用分片上传模式:

  • 上传超过100MB大小的文件。
  • 上传文件之前,无法确定上传文件的大小。
  • 需要较高的吞吐量(采用并发上传分片)。
  • 网络条件较差,和服务器之间的链接经常断开。

使用分片上传时,需要分为如下3个步骤:

  • 初始化一个分片上传任务,使用 createMultipartUpload 接口
  • 使用 UploadPart 接口上传分片
  • 完成分片上传,使用 CompleteMultipartUpload 接口

初始化分片上传

使用Multipart Upload模式传输数据前,必须先初始化一个Multipart Upload事件,Multipart Upload事件可用于上传或复制对象。该操作会返回一个服务器创建的全局唯一的Upload ID,用于标识本次Multipart Upload事件。用户可以根据这个ID来发起相关的操作,如中止Multipart Upload、查询Multipart Upload等。

$bucket = '<your-bucket-name>';
$keyname = '<your-object-key>';
$file_Path = '<your-file-path>';
//指定桶与对象名,与上传对象类似,可以同时设置ACL
$result = $s3->createMultipartUpload([
    'Bucket'       => $bucket,
    'Key'          => $keyName,
]);
//在返回的result中获取用于区分分片上传的唯一标识UploadId,后续的操作中会使用该UploadId
$uploadId = $result['UploadId'];

上传分片

初始化一个Multipart Upload之后,可以根据指定的对象名和Upload ID来分片(Part)上传数据。每一个上传的Part都有一个标识它的号码——分片号(part number,范围是1~10000)。对于同一个Upload ID,该分片号不但唯一标识这一块数据,也标识了这块数据在整个文件内的相对位置,您需要在 uploadPart 时指定Upload ID与分片号。如果用同一个分片号码,上传了新的数据,那么已有的这个分片的数据将被覆盖。除了最后一块part以外,其他的part最小为5MB;最后一块part没有大小限制。分片不需要按顺序上传,甚至可以在不同进程、不同机器上上传,在完成分片上传后服务端会按照分片号排序组成大文件。上传分片部分代码如下:

$file = fopen($filename, 'r');
$partNumber = 1;
while (!feof($file)) {
    // 创建分片复制请求
    $result = $s3->uploadPart([
        'Bucket'     => $bucket,
        'Key'        => $keyName,
        'UploadId'   => $uploadId,                     //uploadId从createMultipartUpload返回值获取
        'PartNumber' => $partNumber,                   //设置分片号
        'Body'       => fread($file, 5 * 1024 * 1024), //读取文件分片,分片大小为5M
    ]);
    $parts['Parts'][$partNumber] = [
        // 记录ETag
        'PartNumber' => $partNumber,
        'ETag' => $result['ETag'],
    ];
    echo "Uploading part {$partNumber} of {$filename}." . "\n";
    $partNumber++;
}
fclose($file);

完成分片上传

所有分片上传或复制完成后,需要调用 complete Multipart Upload 来完成整个文件的 Multipart Upload。在执行该操作时,需要提供所有有效的分片列表(包括分片号和分片 ETAG );服务端收到提交的分片列表后,会逐一验证每个分片的有效性。当所有的数据Part验证通过后,服务端将把这些分片组合成一个完整的 Object。完成分片上传示例代码如下:

$result = $s3->completeMultipartUpload([
    'Bucket'   => $bucket,
    'Key'      => $keyName,
    'UploadId' => $uploadId,
    'MultipartUpload'    => $parts,
]);