繁体   English   中英

如何zlib压缩QByteArray?

[英]How to zlib compress a QByteArray?

我希望在压缩文本时保持地球上其他所有应用程序(包括Web应用程序)之间的互操作性。 由于qCompress和qUncompress似乎与谷物相反,我试图直接从我的Qt应用程序中使用zlib。

我将接受最简单(最简单)的答案,该答案向我展示如何直接使用带有QByteArray的zlib库修改qCompress的输出,以便它可以在Qt应用程序之外使用。

这是我的尴尬尝试:

QByteArray tdata = QString("Oh noes!").toUtf8();
QByteArray cdata;
uLongf len = 12 + 1.002*tdata.length();
compress(&cdata, &len, &tdata, tdata.length());

而错误:

错误:无法将'QByteArray *'转换为'Bytef *'以将参数'1'转换为'int compress(Bytef *,uLongf *,const Bytef *,uLong)'

然后我尝试使用QByteArray :: constData()

compress(cdata.constData(), &len, &tdata, tdata.length());

但得到以下错误:

错误:从'const char *'到'Bytef *'的无效转换

我不知道Bytef是什么,所以我开始查看zlib源代码进行调查。 但我能找到的就是QtSources / src / 3rdparty / zlib / zconf.h

# define Bytef                 z_Bytef

所以现在我迷失了。

基于qUncompress中的这个注释,我认为这很容易。

注意:如果要使用此函数解压缩使用zlib压缩的外部数据,首先需要在包含数据的字节数组前面添加一个四字节头。 标头必须包含未压缩数据的预期长度(以字节为单位),表示为无符号,大端,32位整数。

所以你可以像这样压缩它:

QByteArray tdata = QString("Oh noes!").toUtf8();
QByteArray compressedData = qCompress(tdata);
compressedData.remove(0, 4);

下面是我曾编写的一些代码,它将输入指向字节数组的指针,压缩的字节数和压缩级别,然后使用zlib压缩输入。 结果以字符串形式返回。

 enum compressionLevel
 {
    clFast,
    clSmall,
    clDefault
 };

 const size_t ChunkSize = 262144; //256k default size for chunks fed to zlib

 void compressZlib(const char *s, size_t nbytes, std::string &out, compressionLevel l /*= clDefault*/ )
 {
    int level = Z_DEFAULT_COMPRESSION;
    switch (l)
    {
    case clDefault:
        level = Z_DEFAULT_COMPRESSION; break;
    case clSmall:
        level = Z_BEST_COMPRESSION; break;
    case clFast:
        level = Z_BEST_SPEED; break;
    };

    z_stream strm;
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    int ret = deflateInit(&strm, level);
    if (ret != Z_OK)
    {
        throw std::runtime_error("Error while initializing zlib, error code "+ret);
    }
    size_t toCompress = nbytes;
    char *readp = (char*)s;
    size_t writeOffset = out.size();
    out.reserve((size_t)(nbytes * 0.7));
    while (toCompress > 0)
    {
        size_t toRead = std::min(toCompress,ChunkSize);
        int flush = toRead < toCompress ? Z_NO_FLUSH : Z_FINISH;
        strm.avail_in = toRead;
        strm.next_in = (Bytef*)readp;
        char *writep = new char[ChunkSize];
        do{
            strm.avail_out = ChunkSize;
            strm.next_out = (Bytef*)writep;
            deflate(&strm, flush);
            size_t written = ChunkSize - strm.avail_out;
            out.resize(out.size() + written);
            memcpy(&(out[writeOffset]), writep, written);
            writeOffset += written;
        } while (strm.avail_out == 0);
        delete[] writep;
        readp += toRead;
        toCompress -= toRead;
    }
    (void)deflateEnd(&strm);
 }

也许这可以帮助你解决你的问题,我想使用cdata.constData()你可以直接调用这个函数

只是为了帮助您解决问题的最后一部分:

我不知道Bytef是什么,所以我开始查看zlib源代码进行调查。

有关ByteBytef的定义,请查看Bytef第332和333行,以及第342行:

332    #if !defined(__MACTYPES__)
333    typedef unsigned char  Byte;  /* 8 bits */
...
338    #ifdef SMALL_MEDIUM
339       /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
340    #  define Bytef Byte FAR
341    #else
342       typedef Byte  FAR Bytef;    

FAR的定义用于混合模式MSDOS编程,否则它没有被定义为任何东西(参见zconf.h的第328-330行)。

因此,zlib BytefByte与大多数平台上的unsigned char基本相同。 因此,您应该能够执行以下操作:

QByteArray tdata = QString("Oh noes!").toUtf8();
QByteArray cdata(compressBound(tdata.length()), '\0');
uLongf len = compressBound(tdata.length());
compress(reinterpret_cast<unsigned char*>(cdata.data()), &len, 
         reinterpret_cast<unsigned char*>(tdata.data()), tdata.length());

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM