[英]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源代碼進行調查。
有關Byte
和Bytef
的定義,請查看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 Bytef
和Byte
與大多數平台上的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.