• Better Java GZIP Compression


    Better Java GZIP Compression | > /dev/null

    Better Java GZIP Compression

    April 30, 2010

    I’ve been extending an HTTP server I maintain, and have run into a problem. To compress the response HTTP message contents I use the excellent GZIPOutputStream in the standard Java API. However, recently I have needed fine grain control over the trade-off between compression level and CPU usage on a particularly high load server. To my surprise the GZIPOutputStream class does not allow the compression level to be specified.

    I set out to discover whether it was possible to customise the level of compression provided by GZIPOutputStream. The impatient can skip to the end of this post to get the answers, but the really interesting bit comes next.

    First I took a look at the source code behind GZIPOutputStream. It turns out that it is little more than a Deflater in disguise:

    public class GZIPOutputStream extends DeflaterOutputStream {
        ...
        public GZIPOutputStream(OutputStream out, int size) throws IOException {
            super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size);
            usesDefaultDeflater = true;
            writeHeader();
            crc.reset();
        }
        ...
    }

    The important part to notice in the code above is: new Deflater(Deflater.DEFAULT_COMPRESSION, true). Here a new Deflater instance is being created with a hard coded compression level of Deflater.DEFAULT_COMPRESSION. Not a very flexible design, but it does reveal that the compression level can be customised.

    According to the Java API documentation the Deflater class has a method void setLevel(int level) that allows the compression level to be specified. The compression level must be between 0 and 9. A little arbitrary maybe, but along the lines of what I need (and this API was introduced in Java 1.1).

    Moving up the ancestor chain I took a look at DeflaterOutputStream

    public class DeflaterOutputStream extends FilterOutputStream {
        /**
         * Compressor for this stream.
         */
        protected Deflater def;
        ...
        public DeflaterOutputStream(OutputStream out, Deflater def, int size) {
            ...
            this.def = def;
            ...
        }
    }

    The deflater instance ends up as a variable def in the DeflaterOutputStream class. Although this is well hidden I had two things in my favour: firstly the def variable has protected access, and secondly the GZIPOutputStream is not declared final. This means that any subclass of GZIPOutputStream would have access to def. The two most practical solutions I can think of are presented below:

    Instance Initialiser

    One way to specify the GZIP compression level is to use the so called double brace initialisation. This is quick and easy, and useful if you only need to do it once or twice. Take a look at the following snippet:

    GZIPOutputStream gzip = new GZIPOutputStream(output) {
        {
            def.setLevel(Deflater.BEST_COMPRESSION);
        }
    };

    In this example the first brace creates a new anonymous inner class and the second declares an instance initializer block that is run when the anonymous inner class is instantiated. This type of initializer block is formally called an instance initializer. In the example the compression is overridden to Deflater.BEST_COMPRESSION.

    Subclass

    The instance initialiser approach is useful when using GZIPOutputStream as a one-off, but for a more substantial solution it is better to inherit from GZIPOutputStream and create a useful subclass:

    final class MyGZIPOutputStream extends GZIPOutputStream {
     
        public MyGZIPOutputStream(final OutputStream out) throws IOException {
            super(out);
        }
     
        public void setLevel(int level) {
            def.setLevel(level);
        }
    }

    In this example the void setLevel(int level) method can be used to directly influence the compression level after the GZIP output stream has been instantiated.

  • 相关阅读:
    JAVAWEB使用保存cookie、删除cookie、获取cookie工具类
    JAVA比较指定的两个日期
    编写一个C程序运行时输出 Hello World!
    正确理解以下名词及其含义:1源程序,目标程序,可执行程序2程序编辑,程序编译,程序连接3程序,程序模块,程序文件4函数,主函数,被调用函数,库函数5程序调试,程序测试
    为什么需要计算机语言?高级语言有哪些特点?
    什么是程序?什么是程序设计?
    题解 卡农
    题解 GT考试
    题解 SP6779 【GSS7
    题解 Crash 的文明世界
  • 原文地址:https://www.cnblogs.com/lexus/p/2376767.html
Copyright © 2020-2023  润新知