2012-02-08 1 views
2

표준 스트림에서 한 번에 128 바이트 씩 압축 한 다음 표준 출력으로 출력하려고합니다. (예 : "cat file.txt | java Dict | gzip -d | cmp file.txt", file.txt에는 ASCII 문자가 포함되어 있습니다.)Java : GZIPOutputStream의 Deflater에 setDictionary를 사용할 때의 CRC 오류

또한 끝에서 가져온 32 바이트 사전을 사용해야합니다 각 이전 블록에 대해 이전 128 바이트 블록의 첫 번째 블록은 자신의 첫 32 바이트를 사전으로 사용합니다. 사전을 전혀 설정하지 않으면 압축이 제대로 작동합니다. 그러나 gzip을 사용하면 사전을 설정할 때 "gzip : stdin : invalid compressed data - crc error"라는 데이터 압축 해제 오류가 발생합니다.

코드의 여러 부분을 추가/변경하려했지만 지금까지 아무 것도 작동하지 않았으며 Google에서 솔루션을 찾지 못했습니다.

내가 해봤 ...

  • 추가 "def.reset()는"전에 "def.setDictionary (b)는"근처에게 코드의 바닥이 작동하지 않습니다.
  • 첫 번째 블록 이후의 블록에 대한 사전 설정 만 작동하지 않습니다. (첫 번째 블록에 대해 사전을 사용하지 않습니다.)
  • compress.write (input, 0, bytesRead) 전후에 "input"배열로 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); 
    } 
    } 
} 

답변

1

내가 정확히 내부적으로 모르는 ZLIB 알고리즘 작업하지만 DictGZIPOutputStream에 대한 나의 이해, 당신은 쓰기를 호출 할 때() 방법에 따라, 그 후 쓰기가되면 해당 바이트 배열에 대한 crc가 업데이트됩니다. 다시 updateCRC() 코드를 다시 호출하면 crc가 두 번 업데이트되므로 잘못 될 수 있습니다. 그런 다음 gzip -d를 실행하면 이전 두 번의 crc 업데이트 결과로 gzip이 "유효하지 않은 압축 된 데이터 - crc 오류"라고 표시합니다.

압축기를 사용한 후에 닫지 않은 것으로 나타났습니다. 위에서 붙여 넣은 코드를 실행했을 때 "gzip : stdin : unexpected end of file"오류가 발생했습니다. 그래서 항상 메서드 을 플러시하고 닫기 메서드가 호출되어야합니다. 그 말로는 다음과 같습니다.

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 
+0

안녕하십니까. 답변 해 주셔서 감사합니다. 나는 최근에 당신의 대답을 보았고, 나는이 코드를 꽤 오랫동안 사용하지 않았기 때문에, 그것이 나에게 효과가 있는지 아닌지 알 수있는 기회가 없었습니다. 나는 그것이한다고 가정하고있어, 일단 나 자신을 시험 해보면 나는 그것을 대답으로 표시 할 것이다. –

+0

좋습니다. 도움이 되셨기를 바랍니다. – Jasonw

+0

감사합니다! –

관련 문제