WriteBinaryStream сжат в файл INI?

В Delphi 10.4 я пытаюсь сохранить действительный TPicture, сжатый, в файл INI, пытаясь воспроизвести пример ZLibCompressDecompress из документации:

procedure TForm1.SavePictureToIniFile(const APicture: TPicture);
// https://stackoverflow.com/questions/63216011/tinifile-writebinarystream-creates-exception
var
  LInput: TMemoryStream;
  LOutput: TMemoryStream;
  MyIni: System.IniFiles.TMemIniFile;
  ThisFile: string;
  LZip: TZCompressionStream;
begin
  if FileSaveDialog1.Execute then
    ThisFile := FileSaveDialog1.FileName
  else EXIT;

  LInput := TMemoryStream.Create;
  LOutput := TMemoryStream.Create;
  LZip := TZCompressionStream.Create(clDefault, LOutput);
  try
    APicture.SaveToStream(LInput);
    LInput.Position := 0;
    //LOutput.Position := 0;
    LZip.CopyFrom(LInput, LInput.Size);

    MyIni := TMemIniFile.Create(ThisFile);
    try
      MyIni.WriteBinaryStream('Custom', 'IMG', LOutput);
      MyIni.UpdateFile;
    finally
      MyIni.Free;
    end;
  finally
    LInput.Free;
    LOutput.Free;
    LZip.Free;
  end;
end;

Но поток не сохраняется в файле INI. Полученный INI-файл содержит только эти строки:

[Пользовательский]
IMG=

Итак, как я могу сохранить сжатый поток в файле INI?


person user1580348    schedule 02.08.2020    source источник
comment
Небольшая подсказка: всегда уничтожайте объекты в порядке, обратном их созданию, особенно если они могут зависеть друг от друга. (Это одно из преимуществ постоянного использования одного try..finally для каждого ресурса: тогда вы не сможете ошибиться в порядке!)   -  person Andreas Rejbrand    schedule 02.08.2020
comment
Вы точно не хотите использовать zlib. Изображения уже сжаты.   -  person David Heffernan    schedule 02.08.2020


Ответы (1)


Вам нужно установить LOutput.Position := 0 после строки LZip.CopyFrom, то есть непосредственно перед

MyIni.WriteBinaryStream('Custom', 'IMG', LOutput);
person Andreas Rejbrand    schedule 02.08.2020
comment
Спасибо, сжатие уменьшило размер INI-файла с 840 КБ до 640 КБ (изображение TPicture получено из образа размером 300 КБ). - person user1580348; 02.08.2020
comment
Он будет еще меньше, если вы закодируете сжатые двоичные данные, используя Base64 вместо необработанного шестнадцатеричного кода. - person Andreas Rejbrand; 02.08.2020
comment
Вы правы: Используя ваш пример из вашего ответа на мой предыдущий вопрос (без сжатия LZip), размер INI-файла был уменьшен до 567 КБ. Но как еще больше оптимизировать результат с помощью сжатия LZIP? Можно ли LZip-сжать строку Base64? - person user1580348; 02.08.2020
comment
@ user1580348: Если вы сжимаете строку Base64, вы получаете новый блок двоичных данных, который вам снова нужно закодировать с помощью Base64, чтобы он поместился в файле INI. Я не думаю, что от этого можно много выиграть, уж точно не стоит дополнительных сложностей. Если вы хотите сжать еще больше, вам нужно отказаться от идеи строковых двоичных данных в текстовом файле. Может быть, вы могли бы использовать ZIP-файл, который включает (1) файлы INI для всех текстовых данных и (2) отдельные файлы изображений вместо использования файла INI с двоичными блоками внутри него? - person Andreas Rejbrand; 02.08.2020
comment
Вы правы: я пробовал сжатие строк ZLib, которое действительно создает двоичные символы, которые, как мне кажется, небезопасно хранить в файле INI. Однако я использую формат файла INI для чего-то другого, чего не могу сейчас раскрыть. Так что ваш пример с TBase64Encoding пока лучший компромисс. - person user1580348; 02.08.2020
comment
Если размер является проблемой, существуют другие кодировки преобразования двоичного кода в текст, которые меньше, чем base64, например yEnc. - person Remy Lebeau; 02.08.2020