IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Qt使用zlib压缩

    jakes发表于 2014-10-19 06:35:22
    love 0

    Qt是面向对象语言C++的一个非常强大的库,而zlib是C语言写的。要想在Qt中使用zlib就必须将Qt的中的一些对象转换成C语言的表现形式,而且不能丢失数据。

    比如,Qt中的QString是可以国际化的,在QString内部中,字符是以UTF-16的方式存储的。但是,C类型字符是以ASCII或本地字符集的方式存储的,当将QString转换成C类型字符时必定要将之转换成一种通用格式,UTF-8是最好的选择。
    而且要用QByteArray来存储压缩和解压缩的数据,这样就不需要自己管理内存。

    使用自编译的zlib

    QString source = "要压缩的数据";
    QByteArray ba = source.toUtf8();
    uLong lenOfDest = compressBound(ba.size());
    uLong destLen = lenOfDest;
    QByteArray encrypted;
    encrypted.resize(lenOfDest);
    compress((Bytef*)encrypted.data(), &destLen;, (Bytef*)ba.data(), ba.size());
    encrypted.resize(destLen);

    在QString的toUtf8()方法会将UTF-16转换为UTF-8存储在QByteArray变量中。QByteArray的data()方法可以返回一个可以编辑的char*指针,修改指向的内存数据会影响QByteArray中的内容。
    因为在解压缩的时候同样需要有一个buffer用存放解压后的数据,但没有办法知道原来的长度。普遍的做法是在包头或尾部加入原来的长度。上面的代码可以改为:

    QString source = "要压缩的数据";
    QByteArray ba = source.toUtf8();
    uLong lenOfDest = compressBound(ba.size());
    uLong destLen = lenOfDest;
    QByteArray encrypted;
    encrypted.resize(lenOfDest);
    compress((Bytef*)encrypted.data(), &destLen;, (Bytef*)ba.data(), ba.size());
    QByteArray size(4,0);
    qToBigEndian(ba.size(), (uchar *)size.data());//需要QtEndian头
    encrypted.prepend(size); 
    encrypted.resize(destLen+4);

    解压缩的时候只需要将包的前4字节提取出来,分配相应的存储空间给uncompress解压缩用就可以了。

    QByteArray encrypted;//压缩后的数据
    qint32 size = qFromBigEndian((uchar *)QByteArray(encrypted.data(),4).data());
    QByteArray dest(size, 0);
    uncompress((Bytef*)dest.data(), &size;, (Bytef*)&encrypted.data;()[4], source.size());

     使用Qt内置的压缩函数

    其实在Qt中已经定义了zlib压缩的相关函数,而且对Qt数据类型支持得更好。这两个函数是:qCompress()和qUncompress(),只要引入QByteArray头就可以使用了。函数原型:

    QByteArray qCompress(const QByteArray & data, int compressionLevel = -1);
    QByteArray qCompress(const uchar * data, int nbytes, int compressionLevel = -1);
    QByteArray qUncompress(const QByteArray & data);
    QByteArray qUncompress(const uchar * data, int nbytes);

    使用Qt库定义的qCompress()函数压缩的产生的数据不是标准的zlib压缩数据,因为qCompress()会在数据的头4个字节存储数据的原始长度,而且是以大端(Big-Endin)的方式存储的,其实就跟上节的代码压缩时在包的结构是一样的。
    要想获得标准的zlib压缩包只需去掉头4字节就可以。

    bytearray.remove(0, 4);



沪ICP备19023445号-2号
友情链接