如何将 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 文档为 OutputStreams。这些应该上传到 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 更容易负担额外的内存。

到目前为止,有没有其他可能更有效的方法来实现这一点?

编辑: 我的OutputStreams 是ByteArrayOutputStreams

【问题讨论】:

“我在内存中创建 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的主要内容,如果未能解决你的问题,请参考以下文章

java IO之输出流——OutputStream

java里面OutputStream输出流是怎么清除的?

如何将 Reader 转换为 InputStream 并将 Writer 转换为 OutputStream?

Byte[] 到 InputStream 或 OutputStream

Byte[] 到 InputStream 或 OutputStream

java如何将文件上传其他服务器上 我的文件系统准备单独弄个系统,如何将文件上传到那个系统里