ZLib压缩为数据添加了不需要的字符

时间:2016-09-16 06:42:10

标签: c++ binary zlib

我有以下例程,它只是Uncompresseses一个gz文件,然后Compresseses回到gz。但是,它在数据的开头添加了一些额外的字符。我想知道为什么会这样?

似乎compress_string函数中的某些内容导致了这一点,但我无法找到它。

另外,不确定outbuffer数组是需要更大的尺寸,还是压缩文件的实际尺寸?

#include <iostream>
#include "zlib-1.2.8/zlib.h"
#include <stdexcept>
#include <iomanip>
#include <sstream>
#include <stdio.h>
#include <assert.h>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>

#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
#  include <fcntl.h>
#  include <io.h>
#  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
#  define SET_BINARY_MODE(file)
#endif

#define CHUNK 16384

using namespace std;

bool gzipInflate( const std::string& compressedBytes, std::string& uncompressedBytes ) {
    if ( compressedBytes.size() == 0 ) {
        uncompressedBytes = compressedBytes ;
        return true ;
    }

    uncompressedBytes.clear() ;

    unsigned full_length = compressedBytes.size() ;
    unsigned half_length = compressedBytes.size() / 2;

    unsigned uncompLength = full_length ;
    char* uncomp = (char*) calloc( sizeof(char), uncompLength );

    z_stream strm;
    strm.next_in = (Bytef *) compressedBytes.c_str();
    strm.avail_in = compressedBytes.size() ;
    strm.total_out = 0;
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;

    bool done = false ;

    if (inflateInit2(&strm, (16+MAX_WBITS)) != Z_OK) {
        free( uncomp );
        return false;
    }

    while (!done) {
        // If our output buffer is too small
        if (strm.total_out >= uncompLength ) {
            // Increase size of output buffer
            char* uncomp2 = (char*) calloc( sizeof(char), uncompLength + half_length );
            memcpy( uncomp2, uncomp, uncompLength );
            uncompLength += half_length ;
            free( uncomp );
            uncomp = uncomp2 ;
        }

        strm.next_out = (Bytef *) (uncomp + strm.total_out);
        strm.avail_out = uncompLength - strm.total_out;

        // Inflate another chunk.
        int err = inflate (&strm, Z_SYNC_FLUSH);
        if (err == Z_STREAM_END) done = true;
        else if (err != Z_OK)  {
            break;
        }
    }

    if (inflateEnd (&strm) != Z_OK) {
        free( uncomp );
        return false;
    }

    for ( size_t i=0; i<strm.total_out; ++i ) {
        uncompressedBytes += uncomp[ i ];
    }
    free( uncomp );
    return true ;
}

/** Compress a STL string using zlib with given compression level and return
 * the binary data. */
std::string compress_string(const std::string& str, int compressionlevel = Z_BEST_COMPRESSION)
{
    z_stream zs;                        // z_stream is zlib's control structure
    memset(&zs, 0, sizeof(zs));

    if (deflateInit(&zs, compressionlevel) != Z_OK)
        throw(std::runtime_error("deflateInit failed while compressing."));

    zs.next_in = (Bytef*)str.data();
    zs.avail_in = str.size();           // set the z_stream's input

    int ret;
    char outbuffer[322768];
    std::string outstring;

    // retrieve the compressed bytes blockwise
    do {
        zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
        zs.avail_out = sizeof(outbuffer);

        ret = deflate(&zs, Z_FINISH);

        if (outstring.size() < zs.total_out) {
            // append the block to the output string
            outstring.append(outbuffer,zs.total_out - outstring.size());
        }
    }
    while (ret == Z_OK);

    deflateEnd(&zs);

    if (ret != Z_STREAM_END) {          // an error occurred that was not EOF
        std::ostringstream oss;
        oss << "Exception during zlib compression: (" << ret << ") " << zs.msg;
        throw(std::runtime_error(oss.str()));
    }

    return outstring;
}

/* Reads a file into memory. */
bool loadBinaryFile( const std::string& filename, std::string& contents ) {
    // Open the gzip file in binary mode
    FILE* f = fopen( filename.c_str(), "rb" );
    if ( f == NULL )
        return false ;

    // Clear existing bytes in output vector
    contents.clear();

    // Read all the bytes in the file
    int c = fgetc( f );
    while ( c != EOF ) {
        contents +=  (char) c ;
        c = fgetc( f );
    }
    fclose (f);

    return true ;
}


int main(int argc, char *argv[]) {
    // Read the gzip file data into memory
    std::string fileData ;
    if ( !loadBinaryFile( "myfilein.gz", fileData ) ) {
        printf( "Error loading input file." );
        return 0 ;
    }

    // Uncompress the file data
    std::string data ;
    if ( !gzipInflate( fileData, data ) ) {
        printf( "Error decompressing file." );  
        return 0 ;  
    }  

    // Print the data  
    //printf( "Data: \"" );
    for ( size_t i=0; i<data.size(); ++i ) {  
        printf( "%c", data[i] );
    }  
    //printf ( "\"\n" );


    std::string outy;
    // Compress the file data
    outy = compress_string(data, 0);

    //Write the gzipped data to a file.
    FILE *handleWrite=fopen("myfileout.gz","wb");
    fwrite(outy.data(),outy.size(),1,handleWrite);

    fclose(handleWrite);

    return 0;  
}

1 个答案:

答案 0 :(得分:0)

我不会尝试调试您的代码(这不是此处提供的免费服务),但我可以立即发现您的代码没有按照您的问题声明。您的inflateInit2()会将您设置为解压缩gzip流。但是,deflateInit()将压缩设置为zlib格式,不是 gzip格式。

我建议您阅读zlib.h中的文档。阅读完所有内容后,您可能需要查看此well-commented example of the use of zlib