在 java 中的 GZIPOutputStream 上强制刷新

2022-09-02 21:04:40

我们正在开发一个程序,我们需要刷新(强制压缩和发送数据)GZIPOutputStream。问题是,GZIPOutputStream 的刷新方法无法按预期工作(强制压缩并发送数据),而是流等待更多数据以实现有效的数据压缩。

当您调用 finish 时,数据将被压缩并通过输出流发送,但 GZIPOutputStream(不是底层流)将关闭,因此在创建新的 GZIPOutputStream 之前,我们无法写入更多数据,这会花费时间和性能。

希望任何人都可以对此有所帮助。

此致敬意。


答案 1

我还没有尝试过这个,在我们手头有Java 7之前,这个建议不会有用,但是从中继承的 flush() 方法的文档依赖于在构造时指定的刷新模式,并使用 syncFlush 参数(相关 )来决定是否刷新要压缩的挂起数据。这个论点也被施工时所接受。GZIPOutputStreamDeflaterOutputStreamDeflater#SYNC_FLUSHsyncFlushGZIPOutputStream

这听起来像是你想使用Deflator#SYNC_FLUSH,甚至可能是Defllater#FULL_FLUSH,但是,在深入研究之前,首先尝试使用双参数四参数GZIPOutputStream构造函数并传递参数。这将激活您想要的冲洗行为。truesyncFlush


答案 2

我没有找到工作的另一个答案。它仍然拒绝刷新,因为GZIPOutputStream使用的本机代码保留在数据上。

值得庆幸的是,我发现有人已经实现了一个FlushableGZIPOutputStream作为Apache Tomcat项目的一部分。这是神奇的部分:

@Override
public synchronized void flush() throws IOException {
    if (hasLastByte) {
        // - do not allow the gzip header to be flushed on its own
        // - do not do anything if there is no data to send

        // trick the deflater to flush
        /**
         * Now this is tricky: We force the Deflater to flush its data by
         * switching compression level. As yet, a perplexingly simple workaround
         * for
         * http://developer.java.sun.com/developer/bugParade/bugs/4255743.html
         */
        if (!def.finished()) {
            def.setLevel(Deflater.NO_COMPRESSION);
            flushLastByte();
            flagReenableCompression = true;
        }
    }
    out.flush();
}

你可以在这个罐子中找到整个类(如果你使用Maven):

<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-coyote</artifactId>
    <version>7.0.8</version>
</dependency>

或者只是去获取源代码 FlushableGZIPOutputStream.java

它是在Apache-2.0许可证下发布的。


推荐