猿问

这是 Java 的 Inflater 中的错误还是什么?

我在一些单元测试中就被这个问题困扰了。

我想使用Inflater解压缩一些 ZLIB 压缩的数据,其中原始数据长度是预先知道的。

这(简单)按预期工作

   /*  

     * Decompresses a zlib compressed buffer, with given size of raw data.

     * All data is fed and inflated in full (one step) 

     */

    public static byte[] decompressFull(byte[] comp, int len) throws Exception {

        byte[] res = new byte[len]; // result (uncompressed)

        Inflater inf = new Inflater();

        inf.setInput(comp);

        int n = inf.inflate(res, 0, len);

        if (n != len)

            throw new RuntimeException("didn't inflate all data");

        System.out.println("Data done (full). bytes in :"  + inf.getBytesRead() 

                + " out=" + inf.getBytesWritten()

                + " finished: " + inf.finished());

        // done - the next is not needed, just for checking... 

        //try a final inflate just in case (might trigger ZLIB crc check)

        byte[] buf2 = new byte[6];

        int nx = inf.inflate(buf2);//should give 0

        if (nx != 0)

            throw new RuntimeException("nx=" + nx + " " + Arrays.toString(buf2));

        if (!inf.finished())

            throw new RuntimeException("not finished?");

        inf.end();

        return res;

    }

现在,压缩输入可以是任意大小的块。下面的代码模拟了这样一种情况:除了最后 4 个字节之外,压缩输入被全部馈送,然后一次馈送一个剩余字节。(据我了解,解压缩完整数据不需要 zlib 流的最后 4 个或 5 个字节,但需要它们来检查完整性 - Adler-32 CRC)。


    public static byte[] decompressBytexByte(byte[] comp, int len) throws Exception {

            byte[] res = new byte[len]; // result (uncompressed)

            Inflater inf = new Inflater();

            inf.setInput(comp, 0, comp.length - 4);

            int n = inf.inflate(res, 0, len);

            if (n != len)

        }

嗯,这对我不起作用(Java 1.8.0_181)。充气机还没有完成,Adler CRC 检查还没有完成,看起来;更多:似乎字节没有送入充气机。


更奇怪的是:如果在一次调用中输入尾部 4 个字节,它就会起作用。


您可以在这里尝试: https: //repl.it/@HernanJJ/Inflater-Test


当我一次输入一个字节的整个输入时,甚至会发生更奇怪的事情:有时该行 int nx= inf.inflate(buf2);//should give 0返回非零(当所有数据已经被夸大时)。


这是预期的行为吗?我错过了什么吗?


鸿蒙传说
浏览 168回答 1
1回答

绝地无双

正如@SeanBright已经注意到的,你应该只在Inflater.needsInput()返回 true 时为其提供新的输入。顺序调用setInput将覆盖您之前传递的输入。Javadoc of Inflater.needsInput():如果输入缓冲区中没有数据,则返回 true。这可用于确定是否应调用 #setInput 以提供更多输入。只要你逐字节地输入它,情况总是如此,所以你可能可以跳过检查本身。您可以用此替换该方法的输入设置部分decompressBytexByte(用于完整的逐字节馈送):byte[] res = new byte[len];Inflater inf = new Inflater();int a = 0; // number of bytes that have already been obtainedfor (int p = 0; p < comp.length; p++) {             inf.setInput(comp, p, 1);    a += inf.inflate(res, a, len - a);}
随时随地看视频慕课网APP

相关分类

Java
我要回答