如何使用 ZLIB deflate 方法?

How to use ZLIB deflate method?

我正在尝试使用 zlib 来压缩文本文件。它似乎有点工作,除了我很确定我对写入输出的字节数的计算是错误的。我的代码(由 http://zlib.net/zlib_how.html 指导)如下:

int
deflateFile(
  char *infile,
  char *outfile)
{
    #define CHUNKSIZE 1000
    int n,nr,nw,towrite;
    z_stream strm;
    FILE *fin,*fout;
    BYTE *inbuf,*outbuf;
    int ntot=0;

    printf( "Start doDeflateFile:\n" );

    // ALLOC BUFFERS
    inbuf  = malloc( CHUNKSIZE+1 );
    outbuf = malloc( CHUNKSIZE+1 );

    // OPEN FILES
    fin  = fopen( infile,  "rb" );
    fout = fopen( outfile, "wb" );
    
    // SETUP Z STREAM
    strm.zalloc    = Z_NULL;
    strm.zfree     = Z_NULL;
    strm.opaque    = Z_NULL;    
    strm.avail_in  = CHUNKSIZE; // size of input
    strm.next_in   = inbuf;     // input buffer
    strm.avail_out = CHUNKSIZE; // size of output
    strm.next_out  = outbuf;    // output buffer
    
    deflateInit( &strm, Z_BEST_COMPRESSION );   // init stream level
      
    while( TRUE ) {         // loop til EOF on input file
      // READ NEXT INPUT CHUNK
      nr = fread( inbuf, 1, CHUNKSIZE, fin );
      if( nr <= 0 ) {
        printf( "End of input\n" );
        break;
      }
      printf( "\nread  chunk of  %6d bytes\n", nr );

      printf( "calling deflate...\n" );
      n = deflate(&strm, Z_FINISH);             // call ZLIB deflate

      towrite = CHUNKSIZE - strm.avail_out;     // calc # bytes to write (FIXME???)
      printf( "#bytes to write %6d bytes\n", towrite );
      nw = fwrite( outbuf, 1, towrite, fout );
      if( nw != towrite ) break;
      printf( "wrote chunk of  %6d bytes\n", nw );
      ntot += nw;
    }
        
    deflateEnd(&strm);              // end deflate

    printf( "wrote total of %d bytes\n", ntot );
    printf( "End deflateFile.\n" );

    return( 0 );
}

CHUNKSIZE 为 1000 的 1010 字节输入文件的输出是:

 Start deflateFile:

read  chunk of    1000 bytes
calling deflate...
#bytes to write    200 bytes
wrote chunk of     200 bytes

read  chunk of      10 bytes
calling deflate...
#bytes to write    200 bytes
wrote chunk of     200 bytes
End of input
wrote total of 400 bytes

End deflateFile.

SO #4538586 有点解决了这个问题,但不是很清楚,而且它很旧..
有人能指出我的问题吗?

你应该再读一遍那个页面。这次仔细多了。

您没有在开始时正确设置 avail_in,并且您没有在环形。你唯一做对的事情就是你认为错误的事情,即计算要写出多少字节。你所拥有的甚至不会“有点工作”。

首先,avail_in 必须始终设置为 next_in 处的可用输入量。因此得名 avail_in。您将其设置为 CHUNKSIZE 并调用 inflateInit(),即使该缓冲区中 没有可用的输入

然后你把数据读入输入缓冲区后,你就忽略了nr!您需要将 avail_in 设置为 nr,以指示缓冲区中实际 的数据量。可能小于 CHUNKSIZE.

如果您已经处理了上次读取的所有数据(由 avail_in 表示为零),您应该将数据读入输入缓冲区 只有

deflate() 的调用在循环内完成时,它已更新 next_inavail_innext_outavail_out。要再次使用 inbufoutbuf 缓冲区,您需要将 next_innext_outavail_out 的值重置为您最初设置的值。 avail_in 将设置在 nr 循环的顶部。

您每次都在用 Z_FINISH 呼叫 deflate()!其工作方式是您使用 Z_NO_FLUSH 调用 deflate() 直到提供最后一个输入,然后 然后 使用 Z_FINISH,让它知道完成。 (这就是它被称为那个的原因。)

您的循环将提前退出,因为您需要完成压缩和写入输出,而不仅仅是完成读取输入。

您没有检查 deflate() 的 return 代码。 始终 检查 return 代码。这就是他们在那里的原因。

祝你好运。