【发布时间】:2018-07-09 12:23:29
【问题描述】:
通常当文件必须上传到 s3 时,必须先将其写入磁盘,然后才能使用 TransferManager api 之类的东西上传到云端。如果上传没有按时完成,这会导致数据丢失(应用程序出现故障并在不同的服务器上重新启动等)。所以我想知道是否可以直接通过网络将所需的云位置作为接收器写入流。
【问题讨论】:
标签: amazon-web-services amazon-s3 aws-sdk
通常当文件必须上传到 s3 时,必须先将其写入磁盘,然后才能使用 TransferManager api 之类的东西上传到云端。如果上传没有按时完成,这会导致数据丢失(应用程序出现故障并在不同的服务器上重新启动等)。所以我想知道是否可以直接通过网络将所需的云位置作为接收器写入流。
【问题讨论】:
标签: amazon-web-services amazon-s3 aws-sdk
你没有说你使用的是什么语言,但我会根据你的大小写假设 Java。在这种情况下,答案是肯定的:TransferManager 有一个采用 PutObjectRequest 的 upload() 方法,您可以围绕流构造该对象。
但是,有两个重要的警告。第一个在PutObjectRequest 的文档中:
直接从输入流上传时,必须先指定内容长度,然后才能将数据上传到 Amazon S3
因此,在开始之前,您必须知道要上传多少数据。如果您正在接收来自网络的上传并且有 Content-Length 标头,那么您可以从中获取大小。如果您只是读取任意长度的数据流,则必须先将其写入文件(或者 SDK 会)。
第二个警告是,这并不能防止数据丢失:您的程序仍然可能在读取数据的过程中崩溃。它将阻止的一件事是在将数据存储到 S3 之前向用户返回成功代码,但无论如何您都可以使用文件来执行此操作。
【讨论】:
有可能:
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.build();
s3Client.putObject("bucket", "key", youtINputStream, s3MetData)
【讨论】:
令人惊讶的是,这在标准 Java SDK 中是不可能的(在撰写本文时)。无论如何感谢3rd party library,您至少可以避免将大量数据缓冲到内存或磁盘,因为它在内部缓冲约 5MB 部分并自动上传它们within multipart 为您上传。
SDK 库中还有github issue open,可以关注更新。
【讨论】:
public void saveS3Object(String key, InputStream inputStream) throws Exception {
List<PartETag> partETags = new ArrayList<>();
InitiateMultipartUploadRequest initRequest = new
InitiateMultipartUploadRequest(bucketName, key);
InitiateMultipartUploadResult initResponse =
s3.initiateMultipartUpload(initRequest);
int partSize = 5242880; // Set part size to 5 MB.
try {
byte b[] = new byte[partSize];
int len = 0;
int i = 1;
while ((len = inputStream.read(b)) >= 0) {
// Last part can be less than 5 MB. Adjust part size.
ByteArrayInputStream partInputStream = new ByteArrayInputStream(b,0,len);
UploadPartRequest uploadRequest = new UploadPartRequest()
.withBucketName(bucketName).withKey(key)
.withUploadId(initResponse.getUploadId()).withPartNumber(i)
.withFileOffset(0)
.withInputStream(partInputStream)
.withPartSize(len);
partETags.add(
s3.uploadPart(uploadRequest).getPartETag());
i++;
}
CompleteMultipartUploadRequest compRequest = new
CompleteMultipartUploadRequest(
bucketName,
key,
initResponse.getUploadId(),
partETags);
s3.completeMultipartUpload(compRequest);
} catch (Exception e) {
s3.abortMultipartUpload(new AbortMultipartUploadRequest(
bucketName, key, initResponse.getUploadId()));
}
}
【讨论】: