转自:http://delphi.ktop.com.tw/board.php?cid=31&fid=79&tid=32639
首先说明,这里不是横向比较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秒。
因此,如果把解压缩程序写成下面这样,会非常没有效率:
procedure 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,因此,最有效率的解压程序为:
procedure 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
因此,最有效率的压缩程序为:
procedure ZlibCompressStream2(Source,Dest:TMemoryStream;
CompressLevel:TZCompressionLevel=zcFastest);
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;
===============
久病成良医-多试
發表人 - mustapha.wang 於 2003/06/19 14:55:01