Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Хранение жатых блобов (ZLib), Проблема при декомпрессии 
V
    Опции темы
atr
Дата 3.5.2006, 11:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 3.5.2006

Репутация: нет
Всего: нет



Добрый день!
Prehistory
Пришёл я на работу в контору, с почти готовым продуктом. По ходу процесса нужно хранить отчёты (FastReport 3) в БД (Firebird). Всё в общем работает, но размеры базы перевалили за 1.5 гига за 4 месяца. 
Попытка
Решил я жать готовый отчёт при записи в базу и расжимать при чтении. Написал для сжатия следующее:
Код

procedure TForm1.btn1Click(Sender: TObject);
var
  S:TCompressionStream;
  F:TFileStream;
  M:TMemoryStream;
  V:string;
  Sz:Int64;
begin
   Pr1.Position:=0; 
  try
    if not dbMain.Connected then dbMain.Open;
    dRep.Open;
    dRep.FetchAll;
    pr1.Properties.Max:=dRep.RecordCount;

    while not dRep.Eof do
    begin
      M:=TMemoryStream.Create;
      S:=TCompressionStream.Create(clDefault,M);
      fRepDATA.SaveToStream(S);
      S.Free;
      dRep.Edit;
      fRepDATA.LoadFromStream(M);
      dRep.Post;
      M.Free;
      dRep.Next;
      Pr1.Position:=Pr1.Position+1;
      Application.ProcessMessages;
    end;
  finally
  end;
end;


Базу забэкапил - восстановил - 220 Мб. На первый взгляд, при просмотре BLOB поля где хранятся отчёты типичная картина жатых данных.
Решил восстановить из поля отчёт и показать 
Код

procedure TForm1.e2PropertiesChange(Sender: TObject);
var
  Z:TDecompressionStream;
  M:TMemoryStream;
  
begin
  d1.Locate('ID',e2.EditValue,[]); // находим запись в TFibDataSet
  try
    M:=TMemoryStream.Create;
    fd1DATA.SaveToStream(M); // Считываем данные из Blob в Stream 
    M.Position:=0;
    Z:=TDecompressionStream.Create(M); // Decompress после выполнения Z.Size - EDecompressionError
    Z.Position:=0;
    frpr1.Report.LoadFromStream(Z); // <- тут ошибка хотя через строку выше ясно отчего
    frpr1.Show;
  finally
    M.Free;
    //D.Free;
    Z.Free;
  end;
end;


Не подскажите ли что сделал неверно. Ни разу, до сих пор не работал с ZLib, похоже не понял идеологию. smile 

Спасибо. 
PM MAIL   Вверх
Snowy
Дата 3.5.2006, 12:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 192
Всего: 484



Нет. Так с ZLib работать нельзя. Стримы ZLib'a не являются полноценными стримами.
Поэтому для корректной работы создай 2 мемористрима. А ZLib используй, как посредника между ними.
Для перегона из одного стрима в другой, воспользуйся этим модулем: http://forum.vingrad.ru/index.php?showtopi...st&p=620614 
PM MAIL   Вверх
atr
Дата 3.5.2006, 12:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 3.5.2006

Репутация: нет
Всего: нет



Посмотрел, идея ясна. 
size:dword используется как буфер в Decompress.Create?
... и ещё - процесс сжатия я правильно сделал?   

Это сообщение отредактировал(а) atr - 3.5.2006, 12:39
PM MAIL   Вверх
Snowy
Дата 3.5.2006, 13:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 192
Всего: 484



Цитата(atr @  3.5.2006,  12:34 Найти цитируемый пост)
size:dword используется как буфер в Decompress.Create
Нет. Он сохраняет размер исходного стрима. Не зная этот размер, распаковать невозможно.

Цитата(atr @  3.5.2006,  12:34 Найти цитируемый пост)
... и ещё - процесс сжатия я правильно сделал?
Соответственно нет - нужно сохранять размер.
Ну и компрессию можно было посильнее установить (clMax). 
PM MAIL   Вверх
atr
Дата 3.5.2006, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 3.5.2006

Репутация: нет
Всего: нет



Хм...
Меня терзают смутные сомненья:
Код

constructor TDecompress.Create;    
var    
  Size: dword;    
begin    
  cs:=TDecompressionStream.Create(src);    
  cs.Read(size,SizeOf(Size));    
  dest.CopyFrom(cs,size);    
  cs.Free;    
end;

 
В то же время 
Код

function TDecompressionStream.Read(var Buffer; Count: Longint): Longint;


строка  cs.Read(size,SizeOf(Size)); более чем непонятна... (уж простите за дремучесть smile )

Добавлено @ 13:16 
Ой... смысл вродь такой, перед жатием в стрим пишем размер нежатых данных, а при декомпрессии читаем этот размер, так чтоль? 
PM MAIL   Вверх
Alexeis
Дата 3.5.2006, 13:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 109
Всего: 459



Цитата(atr @  3.5.2006,  12:11 Найти цитируемый пост)
строка  cs.Read(size,SizeOf(Size)); более чем непонятна...

Чтение из потока в переменную, SizeOf даст нам число байт или размер переменной. Прочитав правельный размер данных (хранится в size) мы можем их извлечь из потока.

Добавлено @ 13:17 
Цитата(atr @  3.5.2006,  12:11 Найти цитируемый пост)
Ой... смысл вродь такой, перед жатием в стрим пишем размер нежатых данных, а при декомпрессии читаем этот размер, так чтоль? 
 - КОНЕЧНО!
 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Snowy
Дата 3.5.2006, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 192
Всего: 484



Цитата(atr @  3.5.2006,  13:11 Найти цитируемый пост)
строка  cs.Read(size,SizeOf(Size)); более чем непонятна...
А тут все просто.
Size имеет тип DWORD. 4 байта. В них хранится размер несжатого стрима.
В данной строке мы говорим - прочитай в переменную Size данные, размеров SizeOf(Size) - 4 байта.
Можно было просто написать cs.Read(size, 4);, но правила хорошего тона говорят о необходимости использования SizeOf. Вдруг мы захотим изменить тип Size на word или Int64... 
PM MAIL   Вверх
atr
Дата 3.5.2006, 13:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 3.5.2006

Репутация: нет
Всего: нет



Snowy, alexeis1 - спасибо! Теперь вродь всё ясно. Сейчас пережму данные уже с открытыми глазами smile
Тему пока не закрываю, вдруг что.... 

Я использую ZLibEx, но различий принципиальных с ZLib в технологии похоже нет.
 
PM MAIL   Вверх
atr
Дата 3.5.2006, 16:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 3.5.2006

Репутация: нет
Всего: нет



Переделал сжатие:
Код

procedure TForm1.btn1Click(Sender: TObject);
var
  Z:TZCompressionStream;
  S,D:TMemoryStream;
  Sz:Int64;
begin
  Pr1.Position:=0;
  try
    if not dbMain.Connected then dbMain.Open;
    dRep.Open;
    dRep.FetchAll;
    pr1.Properties.Max:=dRep.RecordCount;

    while not dRep.Eof do
    begin
      S:=TMemoryStream.Create;
      fRepDATA.SaveToStream(S);
      D:=TMemoryStream.Create;
      Sz:=S.Size;
      Z:=TZCompressionStream.Create(D);
      Z.Write(Sz,SizeOf(Sz));
      S.Position:=0;
      Z.CopyFrom(S,Sz);
      Z.Free;
      dRep.Edit;
      fRepDATA.LoadFromStream(D);
      dRep.Post;
      S.Free;
      D.Free;
      dRep.Next;
      Pr1.Position:=Pr1.Position+1;
      Application.ProcessMessages;
    end;
  finally
  end;
end;


Сделал чтение данных и декомпрессию:

Код

procedure TForm1.e2PropertiesChange(Sender: TObject);
var
  Z:TZDecompressionStream;
  S,D:TMemoryStream;
  size:Int64;
begin
  d1.Locate('ID',e2.EditValue,[]);
  try
    S:=TMemoryStream.Create;
    D:=TMemoryStream.Create;
    fd1DATA.SaveToStream(S);
    S.Position:=0;
    Z:=TZDecompressionStream.Create(S);
    Z.Read(size,SizeOf(size));
    d.CopyFrom(Z,Size);

    frpr1.Report.LoadFromStream(D);
    frpr1.Show;
  finally
    S.Free;
    D.Free;
    Z.Free;
  end;
end;


При пошаговопроходе видно, что при создании потока Z получаем исходный размер нежатых данных + 8 байт на размер (Int64). Правильно считывается Z.Read(size,SizeOf(size)).
А в строке d.CopyFrom(Z,Size); выскакивает ошибка "Stream read error". Ведь всё кажись правильно сделал. Не хватает буквально какойто мелочи до получения результата. Абыдна, да...  smile  
PM MAIL   Вверх
atr
Дата 3.5.2006, 17:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 3.5.2006

Репутация: нет
Всего: нет



Всё работает!
17 строка, там где пусто добавить D.Position:=0 и всё нормально.

Храните отчёты в своих базах в сжатом виде!
 smile  
PM MAIL   Вверх
darweeng
Дата 30.12.2012, 22:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 29.12.2012

Репутация: нет
Всего: нет



Доброго времени! Никак не могу перевести в С++ строку №14 из последнего примера:

Код


Z.Read(size,SizeOf(size));



В Билдере выходит  так

Код

Z->Read( TStream, int ) 


что надо писать в скобках?
PM MAIL   Вверх
Alexeis
Дата 7.1.2013, 03:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 109
Всего: 459



В Билдере там void* , принимает указать на область памяти куда будут записаны данные. В делфи там переменная которая принимается по ссылке. В переменную size типа integer записывается размер чего-то там smile .


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1559 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.