0

LZMA を実装したdelphi-zipライブラリのこのスレッド リンクで見つけました。しかし、それから解凍を適切に使用することはできません。このライブラリを使用して、誰かが私のためにちょっとした解凍サンプルを書いてくれませんか?

これが私のコードです。圧縮では機能しますが、解凍では機能せず、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;
4

1 に答える 1

-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;

ここでは、メモリ ストリームはまったく必要ありません。2 つのファイル ストリームが必要です。

直面する大きな問題は、使用することを選択したライブラリでは、解凍するファイルの大きさを知る必要があるということです。使用可能なバイト数を超えて読み取ろうとすると、このライブラリ コードは非終了ループに入ります。したがって、私のCountパラメータはLZMAdecompress.

私の疑いでは、あなたが使用することを選択したライブラリ、または少なくとも使用することを選択したクラスは、あなたのニーズに適していないということです. コードをざっと見ただけですが、よくわかりません。無効なデータが表示されたときに終了しないループを持つ圧縮ライブラリは、あまり役に立ちません。この証拠に基づいて、私はこの図書館を避けます。私があなたなら、LZMA C API を直接呼び出すでしょう。

おそらく、他の問題は、使用しているライブラリに誤った変更を加えたことです。そうしないでください。github から元のバージョンに戻ります。

于 2015-05-20T16:51:57.143 に答える