如何将 Java OutputStream 上传到 AWS S3
Posted
技术标签:
【中文标题】如何将 Java OutputStream 上传到 AWS S3【英文标题】:How to upload a Java OutputStream to AWS S3 【发布时间】:2015-10-26 15:15:50 【问题描述】:我在内存中创建 PDF 文档为 OutputStream
s。这些应该上传到 S3。我的问题是不可能直接从OutputStream
创建PutObjectRequest
(根据this thread in the AWS dev forum)。我在Dropwizard 应用程序中使用aws-java-sdk-s3
v1.10.8。
目前我能看到的两种解决方法是:
-
将
OutputStream
复制到 InputStream
并接受两倍的 RAM 使用量。
将OutputStream
连接到InputStream
并接受额外线程的开销(请参阅this answer)
如果我找不到更好的解决方案,我会选择 #1,因为看起来我比我的设置中的线程/CPU 更容易负担额外的内存。
到目前为止,有没有其他可能更有效的方法来实现这一点?
编辑:
我的OutputStream
s 是ByteArrayOutputStream
s
【问题讨论】:
“我在内存中创建 PDF 文档作为 OutputStreams” - ??一个OutputStream
不存储数据(可能除了ByteArrayOutputStream
,但你会说你在内存中创建它作为一个字节数组)
我使用 ByteArrayOutputStream。很抱歉造成混乱。
我有一个类似的问题 - ***.com/questions/40268320/… 。你能找到解决方案吗?如果没有,你是如何在你的案例中做 #1 的?
@Omnipresent,您可以在下面的我自己的答案中找到我所做的。
请参阅***.com/a/64508183/1704634 以获得允许您直接流式传输到 S3 的解决方案,而无需将整个流存储在字节数组中。如果流太大,自动使用多部分传输。
【参考方案1】:
您的OutputStream
的实际类型是什么?由于它是一个抽象类,因此无法说明数据实际去了哪里(或者它是否去了任何地方)。
但是让我们假设您在谈论ByteArrayOutputStream
,因为它至少将数据保存在内存中(与许多其他人不同)。
如果您从其缓冲区中创建ByteArrayInputStream
,则没有重复的内存。这就是流媒体的全部理念。
【讨论】:
好的,你建议我如何访问缓冲区?您是否建议创建一个子类并为来自ByteArrayOutputStream
的受保护字段 buf
提供公共 getter?
呃,我没有意识到 BAOS 用toByteArray
复制了缓冲区。是的,你应该走子类路线。
没错,因此是子类的想法。
还有几个库已经有一个类似的类(ByteArrayBuffer
似乎是它们的通用名称),它们将直接给出InputStream
。杰克逊至少有一个。
感谢您的意见!我添加了自己的答案以使子类解决方案更加透明。【参考方案2】:
我通过子类化ConvertibleOutputStream
解决了这个问题:
public class ConvertibleOutputStream extends ByteArrayOutputStream
//Craetes InputStream without actually copying the buffer and using up mem for that.
public InputStream toInputStream()
return new ByteArrayInputStream(buf, 0, count);
【讨论】:
这里需要改成return new ByteArrayInputStream(buf, 0, count);
,否则buf
中未分配的数据可能会被视为InputStream中的实际数据。【参考方案3】:
另一种解决方法是使用 s3 的预签名 url 功能。 由于预签名的 url 允许您使用 http put 或 post 将文件上传到 s3,因此可以将您的输出流发送到 HttpURLConnection。 sample code from amazon
【讨论】:
以上是关于如何将 Java OutputStream 上传到 AWS S3的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Reader 转换为 InputStream 并将 Writer 转换为 OutputStream?
Byte[] 到 InputStream 或 OutputStream