zlib解压return-3(z_data_error)

zlib decompression return -3 (z_data_error)

zlib uncompress() return -3 (z_data_error) 当我解压缩数据时。 来自文档:returns Z_DATA_ERROR 如果输入数据已损坏或不完整,

uncompress((Bytef*)uncompressbuffer, &uncompressbuffersize, (const Bytef*)compressbuffer, &compressbuffersize)

在我使用 deflate/inflate 的另一个应用程序中,我得到了同样的错误。

strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = inputLength;
strm.next_in = (unsigned char*) inputBuffer;

ret = inflateInit(&strm);
if (ret != Z_OK)
{
    delete[] uncompressedData;
    return ERROR;
}
/******************************************************/


strm.avail_out = unusedData; 
strm.next_out = (uncompressedData + MIN_CHUNK) - unusedData;

/* run inflate() on input until output buffer not full */
do {
    ret = inflate(&strm, Z_NO_FLUSH);
    assert(ret != Z_STREAM_ERROR);  /* state not clobbered */

    switch (ret)
    {
    case Z_NEED_DICT:
        ret = Z_DATA_ERROR;     /* and fall through */
    case Z_DATA_ERROR:
    case Z_MEM_ERROR:
        (void)inflateEnd(&strm);
        return ret;
    }

} while (strm.avail_out != 0 && ret == Z_OK);

但是

此错误仅发生在我的软件的 x64 版本上。 x86 正常工作。解压后的数据完好无损。压缩和未压缩数据的缓冲区大小正确。 Zlib 已正确编译为 x64。 还有什么可能导致这个问题?有什么提示吗?

带有“uncompress”的示例代码:

#include <iostream>
#include <fstream>
#include <cstdio>
#include <vector>
#include <zlib.h>
#include <assert.h>
#include <cstdlib>

#define CHUNK 16384

const int BUFFERSIZE = 4096;

using namespace std;

void compress(FILE* fin, FILE* fout) {

    char buffer[BUFFERSIZE];
    
    int byte_read = fread(buffer, sizeof(char), BUFFERSIZE, fin);

    
    z_stream strm;
    int ret;
    unsigned have;
    unsigned char* tmp = new unsigned char[CHUNK];

    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    strm.next_in = (unsigned char*)buffer;
    strm.avail_in = byte_read;
    strm.next_out = tmp;
    strm.avail_out = CHUNK;

    ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);

    //first loop: compress input data stream and write on RTDB file
    do
    {

        ret = deflate(&strm, Z_NO_FLUSH);
        assert(ret != Z_STREAM_ERROR);

        have = BUFFERSIZE - strm.avail_out;
        fwrite(tmp, sizeof(char), BUFFERSIZE, fout);

    } while (strm.avail_out == 0);
    //assert(strm.avail_in == 0);

    //second loop: all input data consumed. Flush everything...
    do
    {
        strm.next_out = tmp;
        strm.avail_out = BUFFERSIZE;

        ret = deflate(&strm, Z_FINISH);
        assert(ret != Z_STREAM_ERROR);

        have = BUFFERSIZE - strm.avail_out;
        fwrite(tmp, sizeof(char), BUFFERSIZE, fout);

    } while (ret != Z_STREAM_END);

    (void)deflateEnd(&strm);
    delete tmp;
}

void decompress(FILE* fin, FILE* fout) {

    int status;

    char buffer[BUFFERSIZE];

    int byte_read = fread(buffer, sizeof(char), BUFFERSIZE, fin);

    void* compressedBuffer;
    void* uncompressedBuffer;
    uLongf  compressedBufferSize = BUFFERSIZE;
    uLongf  uncompressedBufferSize = BUFFERSIZE;

    compressedBuffer = malloc(compressedBufferSize);
    uncompressedBuffer = malloc(uncompressedBufferSize);

    status = uncompress((Bytef*)uncompressedBuffer, &uncompressedBufferSize, (const Bytef*)buffer, compressedBufferSize);

    fwrite(uncompressedBuffer, sizeof(char), BUFFERSIZE, fout);

    cout << "Status " << status << endl;
}

int main(int argc, char *argv[]) {
    
    //if (argc == 2)
    //{
    //  if (strcmp(argv[1], "/?") == 0 || strcmp(argv[1], "--help") == 0)
    //  {
    //      cout << "Please give me 1 argument" << endl;
    //      //getchar();
    //      return -1;
    //  }
    //}
    //else
    //{
    //  cout << "Please give me 1 argument" << endl;
    //  //getchar();
    //  return -1;
    //}
    //char *inputdata = argv[1];
    
    //const char *inputdata = "C:\Users\Francesco\source\repos\zlibtest\P0000P0000_no_com-alt.rtdb";
    const char *inputdata = "C:\Users\Francesco\source\repos\zlibtest\AAA.txt";
    //const char *inputdata = "C:\Users\Francesco\source\repos\zlibtest\P0000P0000_no_com-alt.rtdb";
    
    cout << inputdata << endl;
    FILE *fin, *fout, *fdec;
    fopen_s(&fin, inputdata, "r+");

    fopen_s(&fout, "output.txt", "w+");

    compress(fin, fout);

    fclose(fin);
    fclose(fout);

    fopen_s(&fout, "output.txt", "r");

    fopen_s(&fdec, "dec.txt", "w");

    decompress(fout, fdec);
    
    fclose(fout);
    fclose(fdec);
}

您的第一个问题是,当您使用 windows 时,您必须以二进制模式打开压缩文件,否则它将损坏:

fopen_s(&fout, "output.txt", "w+b");
fopen_s(&fout, "output.txt", "rb");

如果您正在压缩的文件不是文本,或者如果它是文本并且您想完美地保存它,您还应该以二进制模式打开输入和 dec 文件。

接下来在compress中你把BUFFERSIZECHUNK搞混了,have = BUFFERSIZE - strm.avail_out;应该是have = CHUNK - strm.avail_out;,然后你需要把have传给fwrite: fwrite(tmp, sizeof(char), have, fout);.

decompress 中,您需要将 uncompressedBufferSize 传递给 fwrite 而不是 BUFFERSIZE

完整的工作代码(有一些额外的更改来修复内存泄漏):

#include <iostream>
#include <fstream>
#include <cstdio>
#include <vector>
#include <zlib.h>
#include <assert.h>
#include <cstdlib>
#include <array>

const size_t CHUNK_SIZE = 16384;

const size_t BUFFER_SIZE = 4096;

void compress(FILE* fin, FILE* fout) {

    std::array<Bytef, BUFFER_SIZE> buffer;

    int byte_read = fread(buffer.data(), sizeof(char), buffer.size(), fin);


    z_stream strm;
    int ret;
    unsigned have;
    std::vector<Bytef> tmp(CHUNK_SIZE);

    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    strm.next_in = buffer.data();
    strm.avail_in = byte_read;
    strm.next_out = tmp.data();
    strm.avail_out = tmp.size();

    ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);

    //first loop: compress input data stream and write on RTDB file
    do
    {

        ret = deflate(&strm, Z_NO_FLUSH);
        assert(ret != Z_STREAM_ERROR);

        have = tmp.size() - strm.avail_out;
        fwrite(tmp.data(), sizeof(char), have, fout);

    } while (strm.avail_out == 0);
    //assert(strm.avail_in == 0);

    //second loop: all input data consumed. Flush everything...
    do
    {
        strm.next_out = tmp.data();
        strm.avail_out = tmp.size();

        ret = deflate(&strm, Z_FINISH);
        assert(ret != Z_STREAM_ERROR);

        have = tmp.size() - strm.avail_out;
        fwrite(tmp.data(), sizeof(char), have, fout);

    } while (ret != Z_STREAM_END);

    (void)deflateEnd(&strm);
}

void decompress(FILE* fin, FILE* fout) {

    int status;

    std::array<Bytef, BUFFER_SIZE> compressedBuffer;
    std::array<Bytef, BUFFER_SIZE> uncompressedBuffer;

    int byte_read = fread(compressedBuffer.data(), sizeof(char), compressedBuffer.size(), fin);

    uLongf  compressedBufferSize = compressedBuffer.size();
    uLongf  uncompressedBufferSize = uncompressedBuffer.size();

    status = uncompress(uncompressedBuffer.data(), &uncompressedBufferSize, compressedBuffer.data(), compressedBufferSize);

    fwrite(uncompressedBuffer.data(), sizeof(char), uncompressedBufferSize, fout);

    std::cout << "Status " << status << "\n";
}

int main(int argc, char* argv[]) {

    const char* inputdata = "C:\Users\alan\source\repos\ConanScratch\main.cpp";

    std::cout << inputdata << "\n";
    FILE* fin, * fout, * fdec;
    fopen_s(&fin, inputdata, "r+b");
    if (!fin)
    {
        std::cout << "unable to open input\n";
        return -1;
    }

    fopen_s(&fout, "output.txt", "w+b");
    if (!fout)
    {
        std::cout << "unable to open output\n";
        return -1;
    }

    compress(fin, fout);

    fclose(fin);
    fclose(fout);

    fopen_s(&fout, "output.txt", "r+b");
    if (!fout)
    {
        std::cout << "unable to open output\n";
        return -1;
    }

    fopen_s(&fdec, "dec.txt", "wb");
    if (!fdec)
    {
        std::cout << "unable to open dec\n";
        return -1;
    }

    decompress(fout, fdec);

    fclose(fout);
    fclose(fdec);
}

您的代码可以通过 boost::iostreams:

大大简化
#include <iostream>
#include <fstream>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filter/zlib.hpp>

int main(int argc, char* argv[])
{
    {
        std::ifstream input("C:\Users\alan\source\repos\ConanScratch\main.cpp", std::ios_base::binary);
        boost::iostreams::filtering_ostream output;
        output.push(boost::iostreams::zlib_compressor{});
        output.push(boost::iostreams::file_sink("output.txt", std::ios_base::out | std::ios_base::binary));
        output << input.rdbuf();
    }
    {
        boost::iostreams::filtering_istream input;
        input.push(boost::iostreams::zlib_decompressor{});
        input.push(boost::iostreams::file_source("output.txt", std::ios_base::in | std::ios_base::binary));
        std::ofstream output("dec.txt", std::ios_base::binary);
        output << input.rdbuf();
    }
}