Qt是面向对象语言C++的一个非常强大的库,而zlib是C语言写的。要想在Qt中使用zlib就必须将Qt的中的一些对象转换成C语言的表现形式,而且不能丢失数据。
比如,Qt中的QString是可以国际化的,在QString内部中,字符是以UTF-16的方式存储的。但是,C类型字符是以ASCII或本地字符集的方式存储的,当将QString转换成C类型字符时必定要将之转换成一种通用格式,UTF-8是最好的选择。
而且要用QByteArray来存储压缩和解压缩的数据,这样就不需要自己管理内存。
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中已经定义了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);