我一直在努力解决Java程序中的内存问题,其中我们将整个文件加载到内存中,对其进行base64编码,然后将其作为表单参数在post请求中使用。由于文件大小极大,这会导致OOME。
我正在研究一种解决方案,能够通过base64编码器将文件流式传输到Http Post请求的请求体中。我注意到所有流行的编码库(Guava、java.util.Base64、android.util.Base64和org.apache.batik.util)中都存在一个共同模式,即如果库支持使用流进行编码,则编码始终通过OutputStream进行,而解码始终通过InputStream进行。
我发现很难找到/确定这些决策背后的原因。考虑到这么多受欢迎且写得很好的库都采用了这种API设计,我认为这其中肯定有理由。虽然将这些解码器之一调整为InputStream或接受InputStream似乎并不是很困难,但我想知道这些编码器被设计成这样是否有一个有效的架构原因。
为什么常见的库都通过OuputStream进行Base64编码,并通过InputStream进行Base64解码?
支持我的说法的示例:
我正在研究一种解决方案,能够通过base64编码器将文件流式传输到Http Post请求的请求体中。我注意到所有流行的编码库(Guava、java.util.Base64、android.util.Base64和org.apache.batik.util)中都存在一个共同模式,即如果库支持使用流进行编码,则编码始终通过OutputStream进行,而解码始终通过InputStream进行。
我发现很难找到/确定这些决策背后的原因。考虑到这么多受欢迎且写得很好的库都采用了这种API设计,我认为这其中肯定有理由。虽然将这些解码器之一调整为InputStream或接受InputStream似乎并不是很困难,但我想知道这些编码器被设计成这样是否有一个有效的架构原因。
为什么常见的库都通过OuputStream进行Base64编码,并通过InputStream进行Base64解码?
支持我的说法的示例:
java.util.Base64
- Base64.Decoder.wrap(InputStream stream)
- Base64.Encoder.wrap(OutputStream stream)
android.util.Base64
- Base64InputStream // An InputStream that does Base64 decoding on the data read through it.
- Base64OutputStream // An OutputStream that does Base64 encoding
google.common.io.BaseEncoding
- decodingStream(Reader reader)
- encodingStream(Writer writer)
org.apache.batik.util
- Base64DecodeStream implements InputStream
- Base64EncodeStream implements OutputStream
OutputStream
包装的问题。 不知何故,我们项目中非常老的http client抽象层没有暴露出包装OutputStream
的方法,但它提供了提供InputStream
的方案。尝试适应这个API是我提出这个问题的原因。@MaartenBodewes 的答案正是我正在寻找的,以确认这是错误的方法。谢谢! - M. WallacePipedInputStream
来反转流并仍然使用OutputStream
,并将base 64编码器包装在其周围。请注意,这是假定多个线程(!)因为如果它阻塞,你就有点麻烦了。如果您必须保持单个线程,则可能需要为应用程序实现更具体的非阻塞InputStream
。当然,PipedInputStream
确实会缓冲。 - Maarten BodewesInputStream
,并问自己:“现在我们该如何通过 HTTP 连接发送它呢?”使用给定的InputStream
是一种逻辑上但错误的解决方案(主要是由于阻塞调用的处理)。在 Java 9 中,有一个(便利)方法transferTo
。它是PipedInputStream
的逻辑对应物,可以帮助程序员连接两者并减轻缓冲/循环的负担。 - Maarten Bodewes