Amazon S3(PHP):复制5GB以上文件失败,寻求分段复制实现方案
解决S3大文件复制问题的PHP实现
S3的copyObject接口仅支持复制≤5GB的文件,超过这个大小必须使用分段复制(Multipart Copy)。下面是修改后的代码,会自动判断文件大小,对大文件执行分段复制:
// STEP #1 - SYSTEM FOLDER BACKUP $objects = $s3->getIterator('ListObjects', array('Bucket' => 'backups', 'Prefix' => $yesterday_system)); $objects = iterator_to_array($objects); // 定义5GB的字节数阈值 $MAX_SINGLE_COPY_SIZE = 5 * 1024 * 1024 * 1024; // 5368709120 // 定义分段大小(建议8MB-100MB,这里用8MB) $PART_SIZE = 8 * 1024 * 1024; // 8388608 // 遍历文件 if (!empty($objects)) { foreach ($objects as $object) { $sourceKey = $object['Key']; $fileSize = $object['Size']; // 处理目标Key list($ignore_1a, $ignore_1b, $key_2) = explode('/', $sourceKey); $targetKey = "_final/{$yesterday_year}/{$yesterday_month}/{$yesterday_day}/system/{$key_2}"; $copySource = "backups/" . rawurlencode($sourceKey); if ($fileSize <= $MAX_SINGLE_COPY_SIZE) { // 小文件用普通复制 $s3->copyObject([ 'ACL' => 'private', 'Bucket' => 'backups', 'CopySource' => $copySource, 'Key' => $targetKey ]); } else { // 大文件执行分段复制 copyLargeS3Object($s3, 'backups', $copySource, $targetKey, $fileSize, $PART_SIZE); } } } /** * 分段复制S3大文件 * @param \Aws\S3\S3Client $s3 S3客户端实例 * @param string $targetBucket 目标Bucket名称 * @param string $copySource 源文件路径(格式:bucket/key) * @param string $targetKey 目标文件Key * @param int $fileSize 源文件大小(字节) * @param int $partSize 每个分段的大小(字节) */ function copyLargeS3Object($s3, $targetBucket, $copySource, $targetKey, $fileSize, $partSize) { // 1. 初始化分段复制任务 $initResponse = $s3->createMultipartUpload([ 'ACL' => 'private', 'Bucket' => $targetBucket, 'Key' => $targetKey ]); $uploadId = $initResponse['UploadId']; $parts = []; $partNumber = 1; $offset = 0; // 2. 逐个复制分段 while ($offset < $fileSize) { $currentPartSize = min($partSize, $fileSize - $offset); // 复制当前分段 $copyResponse = $s3->uploadPartCopy([ 'Bucket' => $targetBucket, 'Key' => $targetKey, 'UploadId' => $uploadId, 'PartNumber' => $partNumber, 'CopySource' => $copySource, 'CopySourceRange' => "bytes={$offset}-" . ($offset + $currentPartSize - 1) ]); $parts[] = [ 'PartNumber' => $partNumber, 'ETag' => $copyResponse['CopyPartResult']['ETag'] ]; $offset += $currentPartSize; $partNumber++; } // 3. 完成分段复制 $s3->completeMultipartUpload([ 'Bucket' => $targetBucket, 'Key' => $targetKey, 'UploadId' => $uploadId, 'MultipartUpload' => ['Parts' => $parts] ]); }
关键说明
- 分段大小可根据实际情况调整(8MB-100MB区间最优),避免过多分段导致性能损耗
- 分段复制分为三步:初始化任务、分块复制、完成上传,每个分段的
ETag必须妥善保存并在最后提交 - 保留了原脚本的文件路径处理逻辑,仅修改了复制逻辑部分
内容的提问来源于stack exchange,提问作者homertino
相关产品推荐
相关产品推荐

