簡體   English   中英

Java:將setDictionary用於GZIPOutputStream的Deflater時出現CRC錯誤

[英]Java: CRC error when using setDictionary for GZIPOutputStream's Deflater

我正在嘗試從標准輸入中獲取數據流,一次將其壓縮為一個128字節塊,然后將其輸出到標准輸出中。 (例如:“ cat file.txt | Java Dict | gzip -d | cmp file.txt”,其中file.txt僅包含一些ASCII字符。)

對於每個后續塊,我還需要使用從每個先前128字節塊的末尾獲取的32字節字典。 (第一個塊使用其自己的前32個字節作為其字典。)當我完全不設置字典時,壓縮效果很好。 但是,當我設置字典時,gzip嘗試解壓縮數據時出現錯誤:“ gzip:stdin:無效的壓縮數據--crc錯誤”。

我曾嘗試添加/更改代碼的幾個部分,但到目前為止沒有任何效果,而且我在Google上找不到任何解決方案。

我試過了...

  • 在代碼底部附近的“ def.setDictionary(b)”之前添加“ def.reset()”無效。
  • 僅在第一個塊之后設置塊的字典不起作用。 (第一個塊不使用字典。)
  • 在Compressor.write(input,0,bytesRead)之前或之后,使用“輸入”數組調用updateCRC不起作用。

我真的很感謝任何建議-有什么明顯的我想念或做錯了嗎?

這就是我的Dict.java文件中的內容:

import java.io.*;
import java.util.zip.GZIPOutputStream;

public class Dict {
  protected static final int BLOCK_SIZE = 128;
  protected static final int DICT_SIZE = 32;

  public static void main(String[] args) {
    InputStream stdinBytes = System.in;
    byte[] input = new byte[BLOCK_SIZE];
    byte[] dict = new byte[DICT_SIZE];
    int bytesRead = 0;

    try {
        DictGZIPOuputStream compressor = new DictGZIPOuputStream(System.out);
        bytesRead = stdinBytes.read(input, 0, BLOCK_SIZE);
        if (bytesRead >= DICT_SIZE) {
            System.arraycopy(input, 0, dict, 0, DICT_SIZE);
            compressor.setDictionary(dict);
        }

        do {
            compressor.write(input, 0, bytesRead);
            compressor.flush();

            if (bytesRead == BLOCK_SIZE) {
                System.arraycopy(input, BLOCK_SIZE-DICT_SIZE-1, dict, 0, DICT_SIZE);
                compressor.setDictionary(dict);
            }
            bytesRead = stdinBytes.read(input, 0, BLOCK_SIZE);
        } while (bytesRead > 0);

        compressor.finish();
    }
    catch (IOException e) {e.printStackTrace();}
  }

  public static class DictGZIPOuputStream extends GZIPOutputStream {
    public DictGZIPOuputStream(OutputStream out) throws IOException {
        super(out);
    }

    public void setDictionary(byte[] b) {
        def.setDictionary(b);
    }
    public void updateCRC(byte[] input) {
        crc.update(input);
    }
  }
}

我不完全知道zlib算法在內部的工作原理,但是基於對DictGZIPOutputStream理解,當您調用write()方法時,在寫入之后,它將為該字節數組更新其crc。 因此,如果您再次在代碼中再次調用updateCRC() ,那么由於crc被更新了兩次,事情就變得錯誤了。 然后,當執行gzip -d時,由於前兩次crc更新,gzip將抱怨“無效的壓縮數據-crc錯誤”

我還注意到,使用壓縮機后您沒有關閉壓縮機。 當我執行上面粘貼的代碼時,它給出了錯誤“ gzip:stdin:文件意外結束”。 因此,請務必確保在最后調用了flush方法 close方法。 話雖如此,我有以下幾點,

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;


public class Dict
{
    protected static final int BLOCK_SIZE = 128;
    protected static final int DICT_DIZE = 32;

    public static void main(String[] args)
    {
        InputStream stdinBytes = System.in;
        byte[] input = new byte[BLOCK_SIZE];
        byte[] dict = new byte[DICT_DIZE];
        int bytesRead = 0;

        try
        {
            DictGZIPOutputStream compressor = new DictGZIPOutputStream(System.out);
            bytesRead = stdinBytes.read(input, 0, BLOCK_SIZE);

            if (bytesRead >= DICT_DIZE)
            {
                System.arraycopy(input, 0, dict, 0, DICT_DIZE);
            }

            do 
            {               
                compressor.write(input, 0, bytesRead);              

                if (bytesRead == BLOCK_SIZE)
                {
                    System.arraycopy(input, BLOCK_SIZE-1, dict, 0, DICT_DIZE);
                    compressor.setDictionary(dict);
                }

                bytesRead = stdinBytes.read(input, 0, BLOCK_SIZE);
            }
            while (bytesRead > 0);
            compressor.flush();         
            compressor.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

    }

    public static class DictGZIPOutputStream extends GZIPOutputStream
    {

        public DictGZIPOutputStream(OutputStream out) throws IOException
        {
            super(out);
        }

        public void setDictionary(byte[] b)
        {
            def.setDictionary(b);
        }

        public void updateCRC(byte[] input)
        {
            crc.update(input);
        }                       
    }

}

控制台上的測試結果。

$ cat file.txt 
hello world, how are you?1e3djw
hello world, how are you?1e3djw adfa asdfas

$ cat file.txt | java Dict | gzip -d | cmp file.txt ; echo $?
0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM