我在使用 AmazonS3.putObject 上传 27MB 文件时看到了这个问题。该命令返回了PutObjectResult,但预期位置没有 S3 对象,结果元数据 (result.getMetadata().getContentLength()) 显示 0 字节。我通过使用 this link 的分段上传解决了这个问题。
private static final Logger LOGGER = LoggerFactory.getLogger(S3Handler.class);
private static final long MAX_SINGLE_PART_UPLOAD_BYTES = 5 * 1024 * 1024;
private final AmazonS3 amazonS3;
public S3Handler(AmazonS3 amazonS3) {
this.amazonS3 = amazonS3;
}
public void putS3Object(String bucket, String objectKey, File file) {
if (file.length() <= MAX_SINGLE_PART_UPLOAD_BYTES) {
putS3ObjectSinglePart(bucket, objectKey, file);
} else {
putS3ObjectMultiPart(bucket, objectKey, file);
}
}
private void putS3ObjectSinglePart(String bucket, String objectKey, File file) {
PutObjectRequest request = new PutObjectRequest(bucket, objectKey, file);
PutObjectResult result = amazonS3.putObject(request);
long bytesPushed = result.getMetadata().getContentLength();
LOGGER.info("Pushed {} bytes to s3://{}/{}", bytesPushed, bucket, objectKey);
}
private void putS3ObjectMultiPart(String bucket, String objectKey, File file) {
long contentLength = file.length();
long partSize = MAX_SINGLE_PART_UPLOAD_BYTES;
List<PartETag> partETags = new ArrayList<>();
// Initiate the multipart upload.
InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucket, objectKey);
InitiateMultipartUploadResult initResponse = amazonS3.initiateMultipartUpload(initRequest);
// Upload the file parts.
long fileOffset = 0;
for (int partNumber = 1; fileOffset < contentLength; ++partNumber) {
// Because the last part could be less than 5 MB, adjust the part size as needed.
partSize = Math.min(partSize, (contentLength - fileOffset));
// Create the request to upload a part.
UploadPartRequest uploadRequest = new UploadPartRequest()
.withBucketName(bucket)
.withKey(objectKey)
.withUploadId(initResponse.getUploadId())
.withPartNumber(partNumber)
.withFileOffset(fileOffset)
.withFile(file)
.withPartSize(partSize);
// Upload the part and add the response's ETag to our list.
UploadPartResult uploadResult = amazonS3.uploadPart(uploadRequest);
LOGGER.info("Uploading part {} of Object s3://{}/{}", partNumber, bucket, objectKey);
partETags.add(uploadResult.getPartETag());
fileOffset += partSize;
}
// Complete the multipart upload.
CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(bucket, objectKey, initResponse.getUploadId(), partETags);
amazonS3.completeMultipartUpload(compRequest);
}