A. 數據流壓縮原理和數據壓縮Zlib的實現
壓縮的本質就是去冗餘,去除信息冗餘,使用最短的編碼保存最完整的數據信息。所以對於不同的場景,壓縮採用的演算法也因時制宜,比如視頻和圖片可以採用有損壓縮,而文本數據採用無損壓縮。壓縮率又取決於信息的冗餘度,也就是內容中重復的比例。那些均勻分布的隨機字元串,壓縮率會降到最低,即香農限
deflate是zip文件的默認演算法。它更是一種數據流壓縮演算法。
LZ77壓縮演算法採用字典的方式進行壓縮,是一種簡單但是很高效的數據壓縮演算法。其方式就是把數據中一些可以組織成短語的字元加入字典。維護三個概念: 短語字典、滑動窗口、向前緩沖區
壓縮的逆過程,通過解碼標記和保持滑動窗口中的符號來更新解壓數據。當解碼字元被標記:將標記編碼成字元拷貝到滑動窗口中,一步一步直到全部翻譯完成
在流式傳輸中,不定長編碼數據的解碼想要保持唯一性,必須滿足唯一可以碼的條件。而異前綴碼就是一種唯一可解碼的候選,當然這樣會增加編碼的長度,卻可以簡化解碼。
huffman編碼是一種基於概率分布的貪心策略最優前綴碼。huffman編碼可以有效的壓縮數據,壓縮率取決於數據本身的信息冗餘度
計算數據中各符號出現的概率,根據概率從小到大,從下往上反向構建構造碼樹,這樣最終得到的編碼的平均長度是最短的。同時也是唯一可譯的
解讀:在一開始,每一個字元已經按照出現概率的大小排好順序,在後續的步驟中,每一次將概率最低的兩棵樹合並,然後用合並後的結果再次排序(為了找出最小的兩棵樹)。在gzip源碼中並沒有專門去排序,而是使用專門的數據結構(比如最小堆或者紅黑樹)。
使用優先隊列實現huffman樹,最後基於Huffman樹最終實現文件壓縮。
具體步驟:
gzip = gzip 頭 + deflate 編碼的實際內容 + gzip 尾
zlib = zlib 頭 + deflate 編碼的實際內容 + zlib 尾
壓縮之前:初始化各種輸入輸出緩沖區;
壓縮:我們可以不斷往這些緩沖區中填充內容,然後由deflate函數進行壓縮或者indeflate函數進行解壓
總結:在調用deflate函數之前,應用程序必須保證至少一個動作被執行(avail_in或者avail_out被設置),用提供更多數據或者消耗更多的數據的方式。avail_out在函數調用之前千萬不能為零。應用程序可以隨時消耗被壓縮的輸出數據
B. C++語言怎麼用zlib庫來解壓.ISO或.zip文件
下面是使用zlib庫的壓縮和解壓縮演示代碼:
#include <stdlib.h>
#include <stdio.h>
#include <zlib.h>
int main(int argc, char* argv[])
{
FILE* file;
uLong flen;
unsigned char* fbuf = NULL;
uLong clen;
unsigned char* cbuf = NULL;
/* 通過命令行參數將srcfile文件的數據壓縮後存放到dstfile文件中 */
if(argc < 3)
{
printf("Usage: zcdemo srcfile dstfile\n");
return -1;
}
if((file = fopen(argv[1], "rb")) == NULL)
{
printf("Can\'t open %s!\n", argv[1]);
return -1;
}
/* 裝載源文件數據到緩沖區 */
fseek(file, 0L, SEEK_END); /* 跳到文件末尾 */
flen = ftell(file); /* 獲取文件長度 */
fseek(file, 0L, SEEK_SET);
if((fbuf = (unsigned char*)malloc(sizeof(unsigned char) * flen)) == NULL)
{
printf("No enough memory!\n");
fclose(file);
return -1;
}
fread(fbuf, sizeof(unsigned char), flen, file);
/* 壓縮數據 */
clen = compressBound(flen);
if((cbuf = (unsigned char*)malloc(sizeof(unsigned char) * clen)) == NULL)
{
printf("No enough memory!\n");
fclose(file);
return -1;
}
if(compress(cbuf, &clen, fbuf, flen) != Z_OK)
{
printf("Compress %s failed!\n", argv[1]);
return -1;
}
fclose(file);
if((file = fopen(argv[2], "wb")) == NULL)
{
printf("Can\'t create %s!\n", argv[2]);
return -1;
}
/* 保存壓縮後的數據到目標文件 */
fwrite(&flen, sizeof(uLong), 1, file); /* 寫入源文件長度 */
fwrite(&clen, sizeof(uLong), 1, file); /* 寫入目標數據長度 */
fwrite(cbuf, sizeof(unsigned char), clen, file);
fclose(file);
free(fbuf);
free(cbuf);
return 0;
}
C. 如何發揮zlib壓縮解壓的最大效
首先說明,這里不是橫向比較zlib與別的引擎(rar,leo,powerarc...),是探索如何發揮zlib壓縮/解壓的最大效率。
先看看如下代碼在效率上的差異:
var MS:TMemoryStream;(1):begin MS:=TMemoryStream.Create; MS.Size:=$400000;//4M------------------------------------------------(2):var i:integer;begin MS:=TMemoryStream.Create; for i:=1 to 1024 do MS.Size:=MS.Size+4096;
你會發現,方法(1)只要1個毫秒,方法(2)卻要20秒。
因此,如果把解壓縮程序寫成下面這樣,會非常沒有效率:
procere ZlibDeCompress(instream,outStream:TStream);var ACS:TDeCompressionStream; buf:array[1..4096] of byte; numread:integer;begin inStream.Position:=0; ACS:=TDeCompressionStream.Create(inStream); try repeat numRead:=ACS.Read(buf,sizeof(buf)); if numread>0 then outStream.Write(buf,numRead); until (numRead=0); finally ACS.Free; end;end;
如果我們知道原始資料的大小,一次確定outStream.Size,效率就可以提高幾十倍。方法很簡單,我們可以在壓縮時,把原始資料的Size寫在壓縮Stream的頭部,如,寫一個Longword的大小,解壓時就可以先讀出Size,因此,最有效率的解壓程序為:
procere ZlibDecompressStream2(Source,Dest:TMemoryStream);var zstream: TZStreamRec; SourceLen,DestLen:LongWord;begin FillChar(zstream,SizeOf(TZStreamRec),0); SourceLen:=Source.Size; Source.Position:=0; Source.Read(DestLen,SizeOf(LongWord)); Dest.Size:=DestLen; zstream.next_in:=Pointer(LongWord(Source.Memory)+SizeOf(LongWord)); zstream.avail_in:=SourceLen-SizeOf(LongWord); zstream.next_out:=Dest.Memory; zstream.avail_out:=DestLen; ZDecompressCheck(InflateInit(zstream)); try ZDecompressCheck(inflate(zstream,Z_NO_FLUSH)); finally ZDecompressCheck(inflateEnd(zstream)); end;end;
用一個4M的文件試試,效率提高近70倍。
同樣道理,在壓縮的時候,如果能預先知道壓縮後的大小,也能提高效率不少,但這似乎是不可能的,也不能盲目的給outStream.Size一個"足夠大"的數值,只能按引擎的原理估算一個最接近的數值,zlib推薦的為:
((SourceLen+(SourceLen div 10)+12)+255) and not 255
因此,最有效率的壓縮程序為:
procere ZlibCompressStream2(Source,Dest:TMemoryStream; CompressLevel:TZCompressi);var zstream: TZStreamRec; SourceLen,DestLen:LongWord;begin FillChar(zstream,SizeOf(TZStreamRec),0); SourceLen:=Source.Size; DestLen:=SizeOf(LongWord)+((SourceLen+(SourceLen div 10)+12)+255) and not 255; Dest.Size:=DestLen; Dest.Position:=0; Dest.Write(SourceLen,Sizeof(LongWord)); zstream.next_in:=Source.Memory; zstream.avail_in:=SourceLen; zstream.next_out:=Pointer(LongWord(Dest.Memory)+SizeOf(LongWord)); zstream.avail_out:=DestLen-SizeOf(longWord); ZCompressCheck(DeflateInit(zstream,ZLevels[CompressLevel])); try ZCompressCheck(deflate(zstream,Z_FINISH)); finally ZCompressCheck(deflateEnd(zstream)); end; Dest.Size:=zstream.total_out+SizeOf(LongWord);end;
D. 簡單介紹VC++6.0下如何使用壓縮庫ZLIB(轉)
2. 用VC++6.0打開
先來看看 zlib 都提供了那些函數, 都在zlib.h中,看到一堆宏不要暈,其實都是為了兼容各種編譯器和一些類型定義.死死抓住那些主要的函數的原型聲明就不會受到這些東西的影響了.
關鍵的函數有那麼幾個:
(1)int compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
把源緩沖壓縮成目的緩沖, 就那麼簡單, 一個函數搞定
(2) int compress2 (Bytef *dest, uLongf *destLen,const Bytef *source, uLong sourceLen,int level);
功能和上一個函數一樣,都一個參數可以指定壓縮質量和壓縮數度之間的關系(0-9)不敢肯定這個參數的話不用太在意它,明白一個道理就好了: 要想得到高的壓縮比就要多花時間
(3) uLong compressBound (uLong sourceLen);
計算需要的緩沖區長度. 假設你在壓縮之前就想知道你的產度為 sourcelen 的數據壓縮後有多大, 可調用這個函數計算一下,這個函數並不能得到精確的結果,但是它可以保證實際輸出長度肯定小於它計算出來的長度
(4) int uncompress (Bytef *dest, uLongf *destLen,const Bytef *source, uLong sourceLen);
解壓縮(看名字就知道了:)
(5) deflateInit() + deflate() + deflateEnd()
3個函數結合使用完成壓縮功能,具體用法看 example.c 的 test_deflate()函數. 其實 compress() 函數內部就是用這3個函數實現的(工程 zlib 的 compress.c 文件)
(6) inflateInit() + inflate() + inflateEnd()
和(5)類似,完成解壓縮功能.
(8) 其他諸如獲得版本等函數就不說了.
E. java 如何用zlib解壓縮tar.gz文件
public static void makeZip(List<File> fileList,String zipPath,boolean isDelete) {
byte[] buf = new byte[1024];
try {
// Create the ZIP file
File zipFile = new File(zipPath);
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));
// Compress the files
for (int i = 0; i < fileList.size(); i++) {
FileInputStream in = new FileInputStream(fileList.get(i));
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(fileList.get(i).getName()));
// Transfer bytes from the file to the ZIP file
int len;
while ( (len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
// Complete the entry
out.closeEntry();
in.close();
}
// Complete the ZIP file
out.close();
System.out.println("壓縮完成.");
//把舊的文件刪除
if(isDelete == true){
for (int i = 0; i < fileList.size(); i++) {
File oldFile = fileList.get(i);
oldFile.delete();
}
}
}
catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args){
File in1=new File("D:\\a.txt");
File in2=new File("D:\\b.txt");
File[] file=new File[]{in1,in2};
File zip=new File("D:\\ab.zip");
IDMZip mgr=new IDMZip();
mgr.ZipFiles(file, zip);
}
這個方法不管你是在windows下還是在linux下,都能正常執行。
F. 關於zlib解壓縮的問題~
壓縮與解壓縮的時候,分別有2個不同的版本,分別是safe和普通的版本。2個版本要對應起來。
你在解壓縮的時候,注意緩沖區大小了嗎?緩沖區夠用了嗎?在壓縮前,保存一下這個壓縮前的原始的長度,然後解壓前,分配一塊至少這么大的內存。
你實際調試過嗎?比如,你可以先去掉文件IO的過程,只是對一個字元串進行壓縮/解壓,然後看看是否正確;然後再加上文件IO,看看存取的過程是否正確。壓縮後的文件應該以二進制方式打開對吧。
G. 如何使用Zlib解壓內存塊中的文件
1 准備工作。 下載zlib.dll。以及相關頭文件。將dll文件及頭文件加入工程。 2 壓縮: 調用函數compress. 形式為 int compress(Byte * dest, uLong* destLen, const Byte *source, ULONG sourceLen); 功能是將source指向的空間,長度為sourceLen的數據進行壓縮,壓縮數據儲存在dest中,長度由參數destLen返回。 如果壓縮出錯,返回對應錯誤號,否則返回0. 3解壓縮: 調用函數uncompress. 形式為 int uncompress(Byte * dest, uLong* destLen, const Byte *source, ULONG sourceLen); 功能是將source指向的空間,長度為sourceLen的數據進行解壓縮,解壓縮後的數據儲存在dest中,長度由參數destLen返回。 如果解壓縮出錯,返回對應錯誤號,否則返回0.
H. 我要使用zlib庫壓縮文件,例如word文檔,png圖片等,那要用哪一個函數呢compress函數只能壓縮裡面的內容!
如果有足夠的緩存,可以一次性地壓縮整個文件,這時候使用compress()壓縮,如果緩存比較小,使用defalate()函數在循環裡面壓縮.
I. 如何用zlib將很多文件或一個文件夾壓縮
新建一個文件夾,把需要壓縮的東西拖到新建文件夾里,然後對著文件夾點右鍵,選擇添加到壓縮文件或者其他壓縮命令,在彈出的界面里點擊確定
J. 關於使用 Zlib + minizip 解壓帶有密碼的 zip 文件
這里只說 Zlib 在 Windows 上的編譯. Linux/Mac 上的不再本次考慮范圍內.
使用zlib庫解壓*.zip文件