Delphi — Сжать список строк с помощью ZLib и сохранить в столбце SQL VARBINARY

#delphi

Вопрос:

Мне нужно взять значения из списка Tstring, сжать его с помощью системы.Библиотеки ZLIb и сохраните его в базе данных SQL Server в виде столбца VARBINARY(MAX).

До сих пор мне удавалось считывать сжатые данные из таблицы SQL, распаковывать их и загружать в список TSTRING. Однако моя проблема заключается в сохранении данных обратно в базу данных, и я не могу заставить их работать. Согласно документам Embarcadero, это должен быть очень простой процесс: http://docwiki.embarcadero.com/CodeExamples/Sydney/en/ZLibCompressDecompress_(Дельфи)

Вот код для обновления моей таблицы SQL. Когда я добираюсь до строки «CompressedStrm.copyFrom(InputStream, InputStream.Size);», я получаю сообщение об ошибке «Ошибка чтения потока».

 procedure TdmMain.SaveSystemSetting(SettingName: string; Settings: TStringList);
var
  InputStream, OutputStream: TMemoryStream;
  CompressedStrm: TCompressionStream;
begin
  InputStream:= TMemoryStream.Create;
  OutputStream:= TMemoryStream.Create;
  try
    Settings.SaveToStream(InputStream, TEncoding.Default);

    CompressedStrm := TCompressionStream.Create(clDefault, OutputStream);
    try
      CompressedStrm.CopyFrom(InputStream, InputStream.Size);
      OutputStream.SaveToFile('c:output.zip');
    finally
      FreeAndNil(CompressedStrm);
    end;

    {save settings to the database}
    qryWork.Close;
    qryWork.SQL.Clear;
    qryWork.SQL.Add('UPDATE SystemSettings');
    qryWork.SQL.Add('   SET Setting = :data');
    qryWork.SQL.Add(' WHERE SettingName = '''   SettingName   '''');
    qryWork.Parameters.ParamByName('data').LoadFromStream(OutputStream, ftBlob);
    qryWork.ExecSQL;
  finally
    FreeAndNil(InputStream);
    FreeAndNil(OutputStream);
  end;
end;
 

Следующий код считывается из базы данных, распаковывает данные и загружает список TStringList — он работает на 100%:

 procedure TdmMain.GetSystemSetting(SettingName: string; var Settings: TStringList);
var
  SettingBlob: TBlobField;
  DecompStream: TDecompressionStream;
  InputStream, OutputStream: TMemoryStream;
begin
  qryWork.Close;
  qryWork.SQL.Clear;
  qryWork.SQL.Add('SELECT Setting');
  qryWork.SQL.Add('  FROM SystemSettings');
  qryWork.SQL.Add(' WHERE SettingName = '''   SettingName   '''');
  qryWork.Open;
  if not qryWork.EOF then
  begin
    SettingBlob := qryWork.FieldByName('Setting') as TBlobField;

    InputStream := TMemoryStream.Create;
    OutputStream := TMemoryStream.Create;
    try
      SettingBlob.SaveToStream(InputStream);
      InputStream.Position := 0;

      DecompStream := TDecompressionStream.Create(InputStream);
      try
        OutputStream.CopyFrom(DecompStream, 0);
        OutputStream.Position := 0;
        Settings.LoadFromStream(OutputStream, TEncoding.Default);
      finally
        FreeAndNil(DecompStream);
      end;
    finally
      FreeAndNil(InputStream);
      FreeAndNil(OutputStream);
    end;
  end;
  qryWork.Close;
end;
 

Комментарии:

1. Зачем вам нужно это делать? Почему бы вам просто не сохранить строки в таблице?

2. О, Оливье, мы с тобой думаем об одном и том же… К сожалению, именно так система была написана 15 лет назад. Я понятия не имею, почему он был разработан таким образом, потому что таблица содержит только 15 записей, а строка, которую она хранит, имеет длину всего несколько сотен символов.

3. Ну, я думаю, ты забыл InputStream.Position := 0; .

4. Собираюсь пнуть себя! Со всеми тестами я, должно быть, удалил «Входной поток. Позиция := 0;» заявление… Положи его обратно и вуаля!

5. Вам не нужны FreeAndNil локальные вары, .Free этого достаточно.

Ответ №1:

Забыл изменить положение входного потока…

   try
    Settings.SaveToStream(InputStream, TEncoding.Default);
    InputStream.Position := 0;
    ...