Как я могу отслеживать и отменять прогресс сжатия Abbrevia?

Delphi Xe4. Существует набор компонентов для сжатия данных: ABBREVIA ( http://tpabbrevia.sourceforge.net/). Он реализует сжатие LZMA и модуль AbLZMA.pas (процедуры сжатия / распаковки Lzma).

Используй это:

...
Uses ablzma;
...
procedure TForm1.Button1Click(Sender: TObject);
var f1,f2:tfilestream;
begin
  f1:=tfilestream.Create('d:\1.test',fmOpenRead);
  f2:=tfilestream.Create('d:\1.lzma',fmCreate);
  LzmaEncodeStream(f1,f2,f1.Size);
  f2.Free;
  f1.Free;
end;
...

Все работает нормально.

Вопросы:

  1. Как добавить код для отображения процента выполнения операции?
  2. Как добавить код для прерывания процесса сжатия?

В модуле AbLZMA.pas (также пытался использовать AbLZMAStream.pas) находится основная процедура LzmaEnc_Encode, которая работает при вызове LzmaEncodeStream:

function LzmaEnc_Encode(p: CLzmaEncHandle; outStream: PISeqOutStream;
  inStream: PISeqInStream; Progress: PICompressProgress;
  Alloc, allocBig: PISzAlloc): SRes; cdecl; external;

Имеет параметр "Progress: PICompressProgress;", где

ICompressProgress = packed record
 Progress: function(p: Pointer; inSize, outSize: Int64): SRes; cdecl;
end;
PICompressProgress = ^ICompressProgress;

Я попытался добавить процедуру в модуль AbLZMA.pas:

function MyProgress(p: Pointer; inSize, outSize: Int64): SRes;cdecl;
begin
// what is "p"?
// form1.caption:=result //? 
end;

...

procedure LzmaEncodeStream(ASourceStream, ATargetStream: TStream; ASourceSize: Int64);
var
  ...
  PMyProgress:PICompressProgress;
begin
  ...
  PMyProgress.Progress:=MyProgress;
  ...
  LzmaCheck(LzmaEnc_Encode(LEncHandle, @LOutStreamRec.Intf, @LInStreamRec.Intf,
    {nil}PMyProgress // this
    ,@DelphiMMInterface, @DelphiMMInterface));
  ...
end;

В этом случае (даже если тело процедуры пустое), выдается ошибка AV. Как получить данные о текущем проценте выполнения?

1 ответ

Решение

Вы должны выделить ICompressProgress переменная. Вы объявили указатель на один, но потом никогда ни на что не указывали.

Сделай это так:

procedure LzmaEncodeStream(ASourceStream, ATargetStream: TStream;
  ASourceSize: Int64);
var
  MyProgress: ICompressProgress;
begin
  ...
  MyProgress.Progress:=MyProgress;
  ...
  LzmaCheck(LzmaEnc_Encode(LEncHandle, @LOutStreamRec.Intf, @LInStreamRec.Intf,
    @MyProgress, @DelphiMMInterface, @DelphiMMInterface));
  ...
end;

Ты звонишь LzmaEnc_Encode который является сырым интерфейсом LZMA C. Документация обратного вызова процесса должна существовать в LZMA SDK, но я пока не могу найти хорошую документацию. Я подозреваю, что вам нужно прочитать реализацию LZMA на C, чтобы разобраться в этом.

Хорошо, вот код, который вызывает ваш обратный вызов прогресса:

for (;;)
{
  res = LzmaEnc_CodeOneBlock(p, False, 0, 0);
  if (res != SZ_OK || p->finished != 0)
    break;
  if (progress != 0)
  {
    res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
    if (res != SZ_OK)
    {
      res = SZ_ERROR_PROGRESS;
      break;
    }
  }
}

Обратный вызов прогресса проходит PICompressProgress в первом параметре. Это позволяет вам объявить ICompressProgress запись с дополнительными полями и, таким образом, позволяет вашей функции обратного вызова получать информацию о состоянии. inSize Параметр - это позиция во входном потоке. Вы можете сделать значение прогресса, разделив inSize по размеру входного потока. И outSize Параметр, предположительно, число байтов, записанных до сих пор в выходной файл.

Если вы вернете любое значение, чем SZ_OK тогда операция будет отменена.

Другие вопросы по тегам