Сжать с ZLIB в массив байтов? - PullRequest
1 голос
/ 17 июня 2020

Могу ли я как-нибудь сжать с помощью Delphi с помощью ZLIB (Deflate with ZLIB headers) и получить массив байтов?

Сейчас я копирую из TMemoryStream, но было бы неплохо не копировать обратно в массив (так что в целом он быстрее)

  PackedStream := TMemoryStream.Create;
  ZLib := TZCompressionStream.Create(PackedStream);
  ZLib.WriteBuffer(UnpackedArray[0], UnpackedArrayLen);
  ZLib.Free;

  PackedArrayLen := PackedStream.Size;
  SetLength(PackedArray, PackedArrayLen);
  PackedStream.Position := 0;
  PackedStream.Read(PackedArray[0], PackedArrayLen);
  PackedStream.Free;

1 Ответ

5 голосов
/ 18 июня 2020

Просто используйте TMemoryStream.Memory как массив байтов , просто не освобождайте поток, пока не закончите использование байтов:

PackedStream := TMemoryStream.Create;
try
  ZLib := TZCompressionStream.Create(PackedStream);
  try
    ZLib.WriteBuffer(UnpackedArray[0], UnpackedArrayLen);
  finally
    ZLib.Free;
  end;
  // use PackedStream.Memory up to PackedStream.Size bytes as needed...
finally
  PackedStream.Free;
end;

В противном случае вы можете использовать TBytesStream вместо TMemoryStream:

PackedStream := TBytesStream.Create;
try
  ZLib := TZCompressionStream.Create(PackedStream);
  try
    ZLib.WriteBuffer(UnpackedArray[0], UnpackedArrayLen);
  finally
    ZLib.Free;
  end;
  // use PackedStream.Bytes up to PackedStream.Size bytes as needed...
finally
  PackedStream.Free;
end;

Или, если у вас есть предварительно выделенный массив байтов, вы можете использовать TCustomMemoryStream, указав ему указатель на этот массив, чтобы он записывал прямо в массив:

type
  TMemoryBufferStream = class(TCustomMemoryStream)
  public
    constructor Create(APtr: Pointer; ASize: NativeInt);
    function Write(const Buffer; Count: Longint): Longint; override;
  end;

constructor TMemoryBufferStream.Create(APtr: Pointer; ASize: NativeInt);
begin
  inherited Create;
  SetPointer(APtr, ASize);
end;

function TMemoryBufferStream.Write(const Buffer; Count: Longint): Longint;
var
  LAvailable: Int64;
  LNumToCopy: Longint;
begin
  Result := 0;
  LAvailable := Size - Position;
  if LAvailable > 0 then
  begin
    LNumToCopy := Count;
    if Int64(LNumToCopy) > LAvailable then
      LNumToCopy := Longint(LAvailable);
    if LNumToCopy > 0 then
    begin
      Move(Buffer, (PByte(Memory) + Position)^, LNumToCopy);
      Seek(LNumToCopy, soCurrent);
      Result := LNumToCopy;
    end;
  end;
end;
PackedStream := TMemoryBufferStream.Create(SomeBuffer, MaxBufferSize);
try
  ZLib := TZCompressionStream.Create(PackedStream);
  try
    ZLib.WriteBuffer(UnpackedArray[0], UnpackedArrayLen);
  finally
    ZLib.Free;
  end;
  // use SomeBuffer up to PackedStream.Size bytes as needed...
finally
  PackedStream.Free;
end;
...