Сегодня я расскажу вам, как пользоваться библиотекой ZLib которая начала поставляться с Delphi начиная с версии 7. Конечно, её можно было использовать и в предыдущих версиях, но для правильного функционирования программы нужно было всё время таскать вместе с программой библиотеку ZLib.dll. В седьмой версии всё стало проще, Delphi внедряла прямо в программу этот модуль с максимальной оптимизацией. Поэтому нам можно не думать о том, как программе носить с собой библиотеку ZLib.dll.
Итак, приступим к делу.
Для того чтобы воспользоваться библиотекой ZLib нам надо подключить модуль ZLib к нашей программе. Этот модуль предоставляет нам два класса-потока: TCompressionStream и TDecompressionStream
НО не для этого я написал эту статью! Многие хотят, чтобы процесс архивации отображался на форме в каком-нибудь компоненте и чтобы форма не зависала во время архивации. Именно для этих целей я напишу модуль прямо на ваших глазах. В этом модуле тоже будет только две функции.
Назавём этот модуль так: ZLibAdvTools.
ZLib
Advanced усовершенствованные
Tools инструменты
ZLibAdvTools.
^^ ^ ^
ZL A T
Сначала про функцию сжатия. Назовём эту фунцкию ZLATCompressFile.
function ZLATCompressFile(
sourcefile:string; //<----|---- это понятно
destinationfile:string; //<----|
compressRatio:integer;// степень сжатия
refreshWnd:boolean;// надо ли обновлять окно во время архивации
needcreate:boolean;// надо ли создавать файл-результат
progress:Pointer;//указатель на компонент прогресса, почему указатель, а не сам
//компонент объясню позже
min_value:integer; //<----|------- это тоже очень сильно пригодится
max_value:integer; //<---|
PositionPropName:string='Progress' // имя свойства прогресса
):integer;// результат
Почему выбрал указатель на компонент прогресса, а не сам компонент. Для увеличения скорости работы функции. Ну, сами подумайте, если вы передадите своему другу на мыло 100 метровый файл или просто отправите на мыло его URL. Здесь та же система: зачем передавать объект, если можно просто указать, где он находится памяти. Теперь зачем нам надо min_value и max_value. Допустим надо отобразить процесс копирования и архивации на компоненте в 100 "делений", тогда копирование будет от 0 до 50, а архивация от 50 до 100, правильно? вот для чего нам нужны эти значения. Параметру PositionPropName уже присвоено значение по умолчанию, поэтому при вызове функции этот параметр нужно ставить, если только свойство, обозначающее положение прогресса имеет другое имя.
Теперь сама процедура:
function ZLATcompressfile;
var
source,dest:TFileStream;
CompresSstream:TCompressionStream;
bytesread:integer;
bytes_read_d:int64; // поясню потом
mainbuffer:array[0..buffer_size-1] of char; // константа нужна для универсальности
//её можно (т.е. нужно) объявить где-нибудь в начале
zena_byta:real; //<-----------------|
interval:integer; //<----------------|--------------терпение, только терпение!!!! всё объясню
Присваивает свойству PropName заданное как СТРОКА!!! у объекта Instance значение Value которое может, быть ЛЮБОГО типа (integer, real, string, array и т.д. и т.п.) Эта процедура использует RTTI информацию объектов и очень сильно загромождает программу и советую её использовать, только если по другому нельзя!! Кстати, тип Variant - это тоже ВЕЛИКОЕ достижение компании Borland. И несколько слов про C++ Builder. По определению: откомпилированный экзешник языка С очень сильно отличается от Pascal'евского, поэтому С остаётся С даже если он от Borland}
SetPropValue(TObject(progress^),'Progress',min_value); // устанавливаем прогресс в начало
if refreshWnd then // если надо обновлять окно, то обновляем
Application.ProcessMessages;
if needprogress then // обновляем прогресс
begin
SetPropValue(
TObject (progress^), // получаем из указателя переменную и преобразуем её к PositionPropName ', // любому классу (какой тип не важно).
min_value+round(Bytes_read_d*zena_byta) //получаем текущее положение
);
end;
until bytesread=0;
except // блин !!! провал
Result:=0;
CompresSstream.free;
source.Free;
dest.Free;
exit;
end;
CompresSstream.free;
if source.Size<>0 then
result:=round((100*dest.Size)/source.size) // результатом будет процент который составляет
// сжатый файл от исходного
else
result:=dest.Size; // опять провал (интересно, тогда что мы сжимали, если размер источника равен нулю)
source . Free ;
dest.Free;
end;
Таким образом Функция возвращает процент, а если оБшибка, то 0.
С декомпрессией будет сложнее.
function ZLATDecompressfile(
sourcefile:string;
destinationfile:string;
refreshWnd:boolean;
needcreate:boolean;
progress:Pointer;
min_value:integer;
max_value:integer ;
PositionPropName:string='Progress'
):boolean;
Здесь почти тоже самое только уже не нужна степень сжатия. Но есть другая проблема. Мы незнаем, сколько будет весить исходный файл, поэтому изначальное значение переменной zena_byta будет заведомо меньше. Например, мы распаковываем файл в 30 МВ, а изначально он весил 60 МВ, поэтому положение прогресса перейдёт за границу max_value. Как же решить эту проблему? Мы после каждой записи из буфера в переменную буде проверять, не превысил ли размер файла-приёмника размера сжатого файла, если да, то мы перерасчитаем переменную zena_byta. Конечно после таких действий при распаковке больших файлов и при слишком большом размере буфера прогресс будет скакать, то взад, то вперёд. Поэтому константе buffer_size лучше присвоить значение 1024 (это самое оптимальное значение - проверено опытом!!!).
Итак, теперь нам надо скопировать файл ZLibAdvTools.pas в папку Lib в корневой папке Delphi и подключить этот модуль в любом месте программы: Uses ZLibAdvTools;