如何高效地将未压缩的InputStream转换为gzip格式的InputStream?

6
一个用户上传了一个大文件到我的网站,我想将该文件gzip压缩并存储到blob中。因此,我有一个未压缩的InputStream和blob需要一个InputStream。我知道如何使用GZIPOutputStream将InputStream压缩为Outputstream,但是如何从gzip'ed OutputStream返回blob所需的InputStream呢?
我找到的唯一方法涉及使用ByteArrayOutputStream,然后使用toByteArray创建新的InputStream。但这意味着我在内存中有整个文件的副本。如果JDBC驱动程序实现也将流转换为byte[],那么我将在内存中拥有两个副本,这不足为奇。

如果您不想将整个文件存储在内存中,则可以将其写入文件。我认为gzip压缩的数据需要被存储到某个地方。 - Vinodh Ramasubramanian
我本来希望能直接将数据流式传输到 blob 中,这样就不需要将整个内容保存在内存中。但看起来这种方法行不通,因为在设置 blob 参数时需要知道长度。从技术上讲,我可以将数据流写入文件,然后获取文件大小,并将其作为输入流重新传输到 blob 中,这样就不需要将整个内容保存在内存中。实际上,这相当于将文件系统用作内存,可能会很有用。 - Brian Deterling
1个回答

4

如果你使用的是Java 1.6,可以使用java.util.zip.DeflaterInputStream。据我所知,这正是你想要的。如果你不能使用1.6,你可以使用java.util.zip.Deflater重新实现DeflaterInputStream。当从BLOB中读取数据时,使用InflaterInputStream作为过滤器来获取原始数据。


我之前不知道那个类。看起来那是正确的解决方案。不幸的是,Blob实现使用长度,而DeflaterInputStream总是返回0或1。我认为我需要长度这一事实意味着无论如何我都不能直接压缩和流式传输数据到Blob中,因为在压缩完成之前无法确定长度。 - Brian Deterling
@Brian 所以在创建 blob 时,你需要传递一个长度和输入流一起吗?InputStream 上没有 length 方法,只有一个可用方法,这意味着与流长度完全不同的东西。 - Geoff Reedy
available() 似乎不能正确返回原始输入流的长度(该流来自HTTP POST)。也许它基于内容长度,或者实际上在我获得它之前在某个上游位置读取了整个流。但是,这对我来说并没有帮助,因为一旦我压缩它,我就不会知道压缩后的大小,直到我已经处理完整个流,此时它已经在内存中,所以我可以将其转换为 byte[]。 - Brian Deterling
在这一点上,你正在处理时间/空间权衡。你可以勇于承担压缩成字节数组的风险,使用更多内存但节省时间。另一个选择是创建一个压缩流,并跳过整个过程以找出压缩版本有多少字节,然后重新创建压缩流并将其传递给 blob,在使用较少内存的同时需要更多时间。 - Geoff Reedy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接