【问题标题】:Delphi LZMA Decompression sampleDelphi LZMA 解压样本
【发布时间】:2015-05-21 02:19:57
【问题描述】:

我在 delphi-zip 库的 this 线程链接中找到了 LZMA 的实现。但我无法从中正确使用解压。 有人可以用这个库为我写一个小解压样本吗?

这是我的代码,它适用于压缩,但不适用于解压缩并返回 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;

【问题讨论】:

  • 你从 decomp 流中读取了 0 个字节,你期望会发生什么?!
  • J := Deca.Read(S2.Bytes, 0, i);。您初始化了I := 0;,从未更改它,因此从流中读取零字节。你得到了你想要的,AFAICT。
  • 所以我猜你需要运行一个循环读取块,直到 Read 返回 0。你也做了很多 Delphi 程序员所做的事情,并且觉得不得不不惜一切代价使用内存流。你在读一个文件?使用 TFileStream。不要先将其全部读入内存。解压时为什么要读入字节流,然后保存到文件中。直接读入以写模式打开的文件流。流是一个抽象层。
  • 也许你可以提供一个样本请求)
  • 我确定您可以将 I 设置为非零值。

标签: delphi lzma


【解决方案1】:

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

我会使用这样的函数:

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;

这里绝对不需要内存流。需要两个文件流。

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

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

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

【讨论】:

  • 谢谢大卫! ))) 对像我这样技能不高的家伙真的很有帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多