前一段时间研究了一下 LZ77 算法,后来又看了一下它的改进版本 LZMA。虽然基本思想已经完全领悟,但是要想具体写出代码还是很有难度,直接研究实现算法又被很多细节阻挡。好在时代不同了,虽然你无法写出具体代码,但是也有现成的库供你调用。
目前开源的比较好用的就是 7-zip 了,这里可以看到中文的介绍:http://sparanoid.com/lab/7z/
同时他还提供了 SDK 供以调用 http://sparanoid.com/lab/7z/sdk.html 。
对于 Delphi 的用户,能够使用的 SDK 在 http://www.birtles.org.uk/programming/ 这里可以下载到。是原生的 Delphi 编写无需第三方库。为了测试我编写了一个Console模式下压缩的小程序,并且在程序中我避免使用这个库内部定义的 Stream 而是直接使用 TMemoryStream。
program LZMAencoder; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, Windows, Classes,ULZMAEncoder,ULZMACommon; var FInput,Foutput:TMemoryStream; //直接使用基础的 MemoryStream encoder:TLZMAEncoder; //编码器 i:integer; //算法方面的要求,最后要补零。具体请查看LZ77描述 begin FInput:=TMemoryStream.Create; //创建和读取一个文件作为压缩的源 FInput.LoadFromFile('C:\Users\Administrator\Documents\RAD Studio\Projects\LZMAEncoder\original.txt'); encoder:=TLZMAEncoder.Create; encoder.SetAlgorithm(2); //设置压缩比,看代码似乎没有真正实现 encoder.SetDictionarySize(1 shl 23); //设置字典大小 encoder.SeNumFastBytes(128); //不知道这个是什么 encoder.SetMatchFinder(1); //找到1个匹配 encoder.SetLcLpPb(3, 0, 2); //应该是LZ77算法用到的几个参数 encoder.SetEndMarkerMode(false); //是否写入流结束标志。因为压缩之后的头上有大小 //所以这里完全不用写入 FOutput:=TMemoryStream.Create; encoder.WriteCoderProperties(FOutput); //写入头信息 for i := 0 to 7 do WriteByte(FOutput,(FInput.Size shr (8 * i)) and $FF); //补全完整流 encoder.Code(Finput, FOutput, -1, -1); //解压过程 encoder.free; FOutput.SaveToFile('C:\Users\Administrator\Documents\RAD Studio\Projects\LZMAEncoder\result.7z'); FOutput.Destroy; Finput.Destroy; readln; end.
压缩结果可以直接用 7-zip 打开(WinZip, WinRar不行)。
原始的 LZMA 代码 LZMA.442b
本文提到的例子:LZMAEncoder
写得很好,想请教下用LZMA SDK的解压代码要如何写?
现在只会用你给的代码压缩,不会解压啊
我看了一下,具体的解压的话,请参考ULZMAAlone.pas中的下面这一段:
if inStream.read(properties, propertiesSize) <> propertiesSize then
raise Exception.Create(‘input .lzma file is too short’);
decoder := TLZMADecoder.Create;
if not decoder.SetDecoderProperties(properties) then
raise Exception.Create(‘Incorrect stream properties’);
outSize := 0;
for i := 0 to 7 do begin
v := {shortint}(ReadByte(inStream));
if v < 0 then raise Exception.Create('Can''t read stream size'); outSize := outSize or v shl (8 * i); end; if not decoder.Code(inStream, outStream, outSize) then raise Exception.Create('Error in data stream'); decoder.Free;