Delphi LZMA解​​压样本

Delphi LZMA Decompression sample

我在 this thread link of the delphi-zip 库中发现了 LZMA 的实现。但是我无法从中正确使用减压。 有人可以使用这个库为我写一个小解压示例吗?

这是我的代码,它适用于压缩但不适用于解压和 return 0 大小

使用 System.Zip.LZMA;

.....

procedure TForm2.CompressProgress(Sender: TObject; const aPosition, aSize, aCompressedSize: UInt64);
begin
end;

procedure TForm2.DecompressProgress(Sender: TObject; const aPosition, aSize: UInt64);
begin
end;

procedure TForm2.CompressButton1Click(Sender: TObject);
var LZI: TLZMAEncoderStream;  OutStream, InStream: TMemoryStream;
begin
     OutStream:= TMemoryStream.Create;
     LZI := TLZMAEncoderStream.Create(OutStream,  CompressProgress);
     InStream:= TMemoryStream.Create;
     InStream.LoadFromFile('1.exe');
     InStream.Position := 0;
     LZI.Write(InStream, InStream.Size);
     OutStream.Position := 0;
     OutStream.SaveToFile('1.exe.lzma');
     InStream.Free;
     OutStream.Free;
     LZI.Free;
end;

procedure TForm2.DecompressButton2Click(Sender: TObject);
var Deca: TLZMADecoderStream;    Str1: TMemoryStream; S2 : TBytesStream;  J, I: Cardinal;
begin
    I := 0;
    Str1 := TMemoryStream.Create;
    Str1.LoadFromFile('1.exe.lzma');
    Str1.Position := 0;
    Deca:= TLZMADecoderStream.Create(Str1, DecompressProgress);

   S2   := TBytesStream.Create;
   J := Deca.Read(S2.Bytes, 0, i);

    Caption := IntToStr(J);

   S2.Position := 0;
   S2.SaveToFile('1.exe');

   Deca.Free;
   Str1.Free;
   S2.Free;
end;

我也试过这样做,但还是不行

procedure TForm2.Button2Click(Sender: TObject);
var Deca: TLZMADecoderStream;    Str1 : TMemoryStream;  S2:TBytesStream;  J, I: Cardinal;
begin
    I := 0;
    Str1 := TMemoryStream.Create;
    Str1.LoadFromFile('1.exe.lzma');
    Str1.Position := 0;
    Deca:= TLZMADecoderStream.Create(Str1, DeProgress);

   S2   := TBytesStream.Create;
   Deca.Position := 0;
   J := Deca.Read(S2.Bytes, 0, Deca.Size);
   Caption := IntToStr(J);
   S2.Position := 0;
   S2.SaveToFile('Dec0.exe');
   Deca.Free;
   Str1.Free;
   S2.Free;
end;

您要求读取零字节,这就是您得到的。您将需要从流中循环读取数据块。一直循环直到 Read returns 为零。请记住,Read returns 读取的字节数。

我会使用这样的函数:

procedure LZMAcompress(InStream, OutStream: TStream);
var
  Encoder: TLZMAEncoderStream;
begin
  Encoder := TLZMAEncoderStream.Create(OutStream, nil);
  try
    Encoder.Write(InStream, InStream.Size);
  finally
    Encoder.Free;
  end;
end;

procedure LZMAdecompress(InStream, OutStream: TStream; Count: Int64);
const
  BufferSize = 1024*1024;
var
  Decoder: TLZMADecoderStream;
  Buffer: TBytes;
  BytesRead, BytesToRead: Integer;
begin
  Decoder := TLZMADecoderStream.Create(InStream, nil);
  try
    SetLength(Buffer, BufferSize);
    repeat
      BytesToRead := Min(Count, BufferSize);
      BytesRead := Decoder.Read(Buffer, BytesToRead);
      OutStream.Write(Buffer, BytesRead);
      dec(Count, BytesRead);
    until Count=0;
  finally
    Decoder.Free;
  end;
end;

这里完全不需要内存流。需要两个文件流。

您将面临的最大问题是您选择使用的库要求您知道要解压的文件有多大。如果您尝试读取比可用字节更多的字节,则此库代码将进入一个非终止循环。因此我的 Count 参数在 LZMAdecompress.

我怀疑您选择使用的库,或者至少是您选择使用的 类,不适合您的需要。我只是快速浏览了代码,但对我来说看起来不太好。当出现无效数据时,任何具有非终止循环的压缩库都不是很有用。我会根据这个证据避开这个图书馆。如果我是你,我会直接打电话给 LZMA C API。

也许您的另一个问题是您对正在使用的库进行了错误的更改。不要那样做。从github回到原来的版本。