| 
| 
 | Вопрос # 953/ вопрос открыт / | 
 |  Здравствуйте, эксперты!Вопрос про архиватор. Мне требуется архивировать файлы различного размера. Это одна из многих функций - далеко не основная. Я использую готовое решение by Andrea Russo - Italy - 2005, выдранное из инета (исходники прикладываю). Проблема в том, что на разархивирование времени уходит болше чем на архивирование. Более того, с ростом размера файла к примеру от 100 мег до 600 мег время разархивирования увеличивается нелинейно (не в 6 а примерно в 15-20 раз) и в конечном итоге составляет до 1,5-2 часа.
 Есть ли другие готовые решения (с исходниками) или как изменить это, чтобы поднять скорость архивирования - разархивирования скажем до 50-100 Мбайт в минуту с разными коэффициентами сжатя.
 Приложение:Переключить в обычный режим <code>unit UtilityPasZlib; // by Andrea Russo - Italy - 2005// email: andrusso@libero.it interface //Unit zlib is icluded into the latest version of Delphi (from Delphi 6), but in old versions is//included into the Delphi cd.// Otherwise if do you want to use paszlib library change the uses. //If do you want to use zlib included into Delphi uses zlib, Classes; //If do you want to use paszlib library//uses dzlib, Classes; type TCompLevel = (clNone, clFastest, clDefault, clMax); procedure CompressFile(const sFileIn : string; const sFileOut : string; const Level : TCompLevel =
clDefault);procedure UnCompressFile(const sFileIn : string; const sFileOut : string); procedure CompressStream(inStream, outStream :TStream; const Level : TCompLevel = clDefault);procedure ExpandStream(inStream, outStream :TStream); implementation procedure CompressFile(const sFileIn : string; const sFileOut : string; const Level : TCompLevel =
clDefault);var inStream, outStream: TMemoryStream;begin inStream:=TMemoryStream.Create; outStream:=TMemoryStream.Create; try  inStream.LoadFromFile(sFileIn);  with TCompressionStream.Create(TCompressionLevel(Level), outStream) do   try    CopyFrom(inStream, inStream.Size);   finally    Free;   end;   outStream.SaveToFile(sFileOut);  finally   outStream.Free;   inStream.Free;  end;end; procedure UnCompressFile(const sFileIn : string; const sFileOut : string);var inStream, outStream: TMemoryStream;begin inStream:=TMemoryStream.Create; outStream:=TMemoryStream.Create; try  inStream.LoadFromFile(sFileIn);  ExpandStream(inStream, outStream);  outStream.SaveToFile(sFileOut); finally  inStream.Free;  outStream.Free; end;end; procedure CompressStream(inStream, outStream :TStream; const Level : TCompLevel = clDefault);begin with TCompressionStream.Create(TCompressionLevel(Level), outStream) do  try   CopyFrom(inStream, inStream.Size);  finally   Free;  end;end; procedure ExpandStream(inStream, outStream :TStream);const BufferSize = 4096;var Count: integer; ZStream: TDecompressionStream; Buffer: array[0..BufferSize-1] of Byte;begin ZStream:=TDecompressionStream.Create(InStream); try  while true do   begin    Count:=ZStream.Read(Buffer, BufferSize);    if Count<>0    then OutStream.WriteBuffer(Buffer, Count)    else Break;   end;  finally   ZStream.Free;  end;end; end.</code>
|  |   Вопрос задал: Popovich E.V. (статус: Посетитель)Вопрос отправлен: 3 октября 2007, 15:58
 Состояние вопроса: открыт, ответов: 4.
 |  Ответ #1. Отвечает эксперт: Вадим К Здравствуйте, Popovich E.V.!Причиной стремительного замедления может быть неудачная работа с памятью
 для примера, потестируйте код
 
 s:string;
begin
s:='';
for i:=1 to 1000 do s:=s+'*';и  код 
 s:string;
begin
s:='';
Setlength(s,1000)
for i:=1 to 1000 do s[i]:='*';Хотя оба кода делают одно и тоже, но при увеличении строки первый код начинает подтормаживать. причина - постоянное копирование строки. И хотя это жутко утрированный пример, но он в том или ином подобии появляется в разных примерах.
 Второй причиной может быть то, что библиотека не расчитана на такие объёмы. тоесть при таких объемах данных может не совсем правильно заполнятся внутринее структуры, неправильно срабатывать оптимизация, которая хорошо работала на маленьких объема.
 
 Есть альтернативная, бесплатная библиотека http://www.delphilab.ru/content/view/72/73/
 скорость достаточно приличная (на 2ГГц даёт до мегабайта в секунду на распаковку)
 Работает достаточно хорошо
 
|  | Ответ отправил: Вадим К (статус: Академик)Время отправки: 3 октября 2007, 16:22
 Оценка за ответ: 4
 |  Ответ #2. Отвечает эксперт: Feniks Здравствуйте, Popovich E.V.!Сегодня в инете встретил книгу "Методы сжатия данных. Устройство архиваторов, сжатие изображений и видео" по этому адресу http://ru-admin.net/2007/10/03/metody-szhatija-dannykh.-ustrojjstvo.html
 А кто Вам мешает использовать уже существующие архиваторы ? Ведь они все поддерживают работу с командной строкой, например RAR. Он есть и консольный. Консольным с помощью параметров командной строки пакует, а для распаковки используете его библиотеку unrar.dll Пример ее использования см. в Приложении.
 Еще попробуйте пару компонентов http://depositfiles.com/files/1951946
 Приложение:Переключить в обычный режим function RAROpenArchive(ArchiveData : Pointer): Integer; stdcall;external 'unrar.dll' name 'RAROpenArchive';  function RARCloseArchive(hArcData : Integer): Integer; stdcall;external 'unrar.dll' name 'RARCloseArchive'; function RARReadHeader(hArcData : Integer; HeaderData : Pointer): Integer; stdcall;external 'unrar.dll' name 'RARReadHeader'; function RARProcessFile(hArcData : Integer; Operation : Integer; DestPath : Pointer;DestName : Pointer): Integer; stdcall;external 'unrar.dll' name 'RARProcessFile';  const ERAR_END_ARCHIVE = 10;ERAR_NO_MEMORY = 11;ERAR_BAD_DATA = 12;ERAR_BAD_ARCHIVE = 13;ERAR_UNKNOWN_FORMAT = 14;ERAR_EOPEN = 15;ERAR_ECREATE = 16;ERAR_ECLOSE = 17;ERAR_EREAD = 18;ERAR_EWRITE = 19;ERAR_SMALL_BUF = 20; RAR_OM_LIST = 0;RAR_OM_EXTRACT = 1;RAR_SKIP = 0;RAR_TEST = 1;RAR_EXTRACT = 2;RAR_VOL_ASK = 0;RAR_VOL_NOTIFY = 1;  type Char260 = Array [1..260] of Char;  TRAROpenArchiveData = record   OpenMode : Cardinal;  OpenResult : Cardinal;  CmtBuf : PChar;  CmtBufSize : Cardinal;  CmtSize : Cardinal;  CmtState : Cardinal;end;   TRARHeaderData = record  ArcName : Char260;  FileName : Char260;  Flags : Cardinal;  PackSize : Cardinal;  UnpSize : Cardinal;  HostOS : Cardinal;  FileCRC : Cardinal;  FileTime : Cardinal;  UnpVer : Cardinal;  Method : Cardinal;  FileAttr : Cardinal;  CmtBuf : PChar;  CmtBufSize : Cardinal;  CmtSize : Cardinal;  CmtState : Cardinal;end;  var RARExtract : boolean;RAROpenArchiveData : TRAROpenArchiveData;RARComment : array [1..256] of Char;RARHeaderData : TRARHeaderData;  ...  procedure ExtractRARArchive;varsDir : string;s : string;sTest : string;iTest : integer;bTestDone : boolean;RARhnd : Integer;RARrc : Integer;PDestPath : Char260; beginRARExtract:=TRUE;lKBWritten:=0;ProgressBar2.Position := 0;ProgressBar2.Max := lTotalSize;RARStartTime:=Time; RAROpenArchiveData.OpenResult:=99; RAROpenArchiveData.ArcName:= @RARFileName;RAROpenArchiveData.CmtBuf := @RARComment; RAROpenArchiveData.CmtBufSize := 255;   RARhnd := RAROpenArchive (@RAROpenArchiveData);If RAROpenArchiveData.OpenResult <> 0 thenbegin  case RAROpenArchiveData.OpenResult of   ERAR_NO_MEMORY : s:='Not enough memory to initialize data structures';   ERAR_BAD_DATA : s:='Archive header broken';   ERAR_BAD_ARCHIVE : s:='File is not valid RAR archive';   ERAR_EOPEN : s:='File open error';  end;  MessageDlg('Unable to open rar archive: ' + s + '!',mtError, [mbOK], 0);end; RARSetProcessDataProc(RARhnd,@Form.OnRarStatus);StrPCopy(@PDestPath, EInstallPath.Text); repeat   if RARrc <> ERAR_END_ARCHIVE then  begin   ProgressBar1.Position := 0;   ProgressBar1.Max := RARHeaderData.UnpSize;   s:=RARHeaderData.FileName;   lblCurrentFile.Caption := s;   lKBytesDone := 0;  end;   if RARrc = 0 then  RARrc:=RARProcessFile (RARhnd, RAR_EXTRACT, @PDestPath, nil);  if (RARrc <> 0) and (RARrc <> ERAR_END_ARCHIVE) then  begin   MessageDlg('An Error occured during extracting of ' + sTest+'!' + #13#10 +   'RARProcessFile: ' + MakeItAString(RARrc),mtError, [mbOK], 0);  end;until RARrc <> 0;  If RARCloseArchive(RARhnd) <> 0 thenbegin  MessageDlg('Unable to close rar archive!',mtError, [mbOK], 0);end;end; // ExtractRARArchive
|  | Ответ отправил: Feniks (статус: Бакалавр)Время отправки: 3 октября 2007, 16:39
 
 |  Ответ #3. Отвечает эксперт: min@y™ Зайди-ка вот сюды. Там есть куча того, что тебе надо. 
|  | Ответ отправил: min@y™ (статус: Доктор наук)Время отправки: 3 октября 2007, 16:50
 
 |  Ответ #4. Отвечает эксперт: Помфюк Владимир Степанович Здравствуйте, Popovich E.V.!В Вашем примере совершенно непонятно зачем используется TMemoryStream. Возможно при болших обьёмах именно он и "тормозит процесс". Попробуйте так (в приложении). У меня работает, правда, с алгоритмом упаковки bz2 (BZip2 unit by Edison Mera, окуда качал не помню).
 Приложение:Переключить в обычный режим    zs:TCompressionStream; ifl,ofl:TFileStream;begin ifl:=TFileStream.Create(InFileName,fmOpenRead); ofl:=TFileStream.Create(OutFileName,fmCreate or fmOpenReadWrite); zs:=TCompressionStream.Create(CompressionLefel,ofl); zs.CopyFrom(ifl,ifl.Size); ifl.Destroy; zs.Destroy; ofl.Destroy;end  
 Мини-форум вопросаВсего сообщений: 1; последнее сообщение — 3 октября 2007, 16:45; участников в обсуждении: 1. 
|   | Feniks (статус: Бакалавр), 3 октября 2007, 16:45 [#1]:В догонку, зыбал вставить... 
 В Delphi 7 официально включена поддержка библиотеки сжатия ZLib. Если у вас более старшая версия посмотрите модули ZLib в дестрибутиве среды (они должны быть на диске но подключать прийдеться самому).
 
 Библиотеки под разные платформы, среды разработок и документация на сайте www.gzip.org/zlib.
 
 Степень сжатия превосходит алгоритм zip. Максимальная степень сжатия по алгоритму ZLib приближается к степени сжатия упаковщиком RAR.
 
 Модули Zlib, ZlibConst.
 
 При использовании необходимо подключить в описании Uses модуль ZLib.
 
 пример использования:
 
 Компресия одного потока в другой:
 
 ComressStream( aSource, aTarget : TStream; compressionRate : TCompressionLevel );
 var comprStream : TCompressionStream;
 begin
 // compression level : (clNone, clFastest, clDefault, clMax)
 comprStream := TCompressionStream.Create( compressionRate, aTarget );
 try
 comprStream.CopyFrom( aSource, aSource.Size );
 comprStream.CompressionRate;
 finally
 comprStream.Free;
 End;
 End;
 
 Декомпресия одного потока в другой:
 
 DecompressStream(aSource, aTarget: TStream);
 var decompStream : TDecompressionStream;
 nRead : Integer;
 buffer : array[0..1023] of Char;
 begin
 decompStream := TDecompressionStream.Create( aSource );
 try
 repeat
 nRead:=decompStream.Read( buffer, 1024 );
 aTarget.Write( buffer, nRead );
 Until nRead = 0;
 finally
 decompStream.Free;
 End;
 End;
 
 P.S. ©Drkb::03193 / Взято из http://forum.sources.ru
 |  Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте. |