Последние записи
- TChromium (CEF3), сохранение изображений
- Как в Delphi XE обнулить таймер?
- Изменить цвет шрифта TextBox на форме
- Ресайз PNG без потери прозрачности
- Вывод на печать графического файла
- Взаимодействие через командную строку
- Перенести программу из Delphi в Lazarus
- Определить текущую ОС
- Автоматическая смена языка (раскладки клавиатуры)
- Сравнение языков на массивах. Часть 2
Интенсив по Python: Работа с API и фреймворками 24-26 ИЮНЯ 2022. Знаете Python, но хотите расширить свои навыки?
Slurm подготовили для вас особенный продукт! Оставить заявку по ссылке - https://slurm.club/3MeqNEk
Online-курс Java с оплатой после трудоустройства. Каждый выпускник получает предложение о работе
И зарплату на 30% выше ожидаемой, подробнее на сайте академии, ссылка - ttps://clck.ru/fCrQw
31st
Дек
Модуль архивации – создание и использование Delphi
Posted by Chas under Исходники, Статьи
как пользоваться библиотекой ZLib которая начала поставляться с Delphi начиная с версии 7. Конечно, её можно было использовать и в предыдущих версиях, но для правильного функционирования программы нужно было всё время таскать вместе с программой библиотеку ZLib.dll. В седьмой версии всё стало проще, Delphi внедряла прямо в программу этот модуль с максимальной оптимизацией. Поэтому нам можно не думать о том, как программе носить с собой библиотеку ZLib.dll.
Итак, приступим к делу.
Для того чтобы воспользоваться библиотекой ZLib нам надо подключить модуль ZLib к нашей программе.
Этот модуль предоставляет нам два класса-потока:
TCompressionStream
и
TDecompressionStream
Вот как будет выглядеть сжатие файла:
var
source,dest:TFileStream;//поток-источноик, поток-приёмник
CompresSstream:TCompressionStream; // поток – архиватор
bytesread:integer;
mainbuffer:array[0..1023] of char; // буфер
begin
source:=TFileStream.Create(’< Путь к файлу >’,fmOpenRead); // создаём поток – источник
dest:=TFileStream.Create(’< Путь к результату >’,fmCreate); // создаём поток – приёмник
CompresSstream:=TCompressionStream.Create(clMax,dest);// создаём поток – архиватор c // максимальной степенью сжатия
try // НА ВСЯКИЙ ПОЖАРНЫЙ
repeat
bytesread:=source.Read(mainbuffer,buffer_size); // считываем из источника в буфер
CompresSstream.Write(mainbuffer,bytesread); // записываем из буфера в поток – архиватор
until bytesread<1024; // всё это до тех пор пока весь источник не будет считан
except // если всё же возникнет какая-нибудь оБшибка!!!
CompresSstream.free;
source.Free;
dest.Free;
exit;
end; // всё прошло успешно
CompresSstream.free;
source.Free;
dest.Free;
end;
Примерно так-же будет выглядеть распаковка файла
var
source,dest:TFileStream;
decompressStream:TDecompressionStream; //
bytesread:integer;
mainbuffer:array[0..1023] of char;
begin
source:=TFileStream.Create(’< Путь к файлу >’,fmOpenRead);
dest:=TFileStream.Create(’< Путь к результату >’,fmCreate);
decompressStream:=TDecompressionStream.Create(source); //
try
repeat
bytesread:=decompressStream.Read(mainbuffer,buffer_size);
dest.Write(mainbuffer,bytesread);
until bytesread<1024;
except
decompressStream.Free;
source.Free;
dest.Free;
exit;
end;
decompressStream.Free;
source.Free;
dest.Free;
end;
НО не для этого я написал эту статью! Многие хотят, чтобы процесс архивации отображался на форме в каком-нибудь компоненте и чтобы форма не зависала во время архивации. Именно для этих целей я напишу модуль прямо на ваших глазах. В этом модуле тоже будет только две функции.
Назавём этот модуль так: 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; //<—————-|————–терпение, только терпение!!!! всё объясню
needProgress:boolean; //<———|
begin
needProgress:=false;// обнуляю
source:=TFileStream.Create(sourcefile,fmOpenRead); //
if needcreate then
dest:=TFileStream.Create(destinationfile,fmCreate) // создаём объект вместе с созданием файла
else
dest:=TFileStream.Create(destinationfile,fmOpenWrite); // открываем в режиме чтения / записи
if compressRatio=0 then
CompresSstream:=TCompressionStream.Create(clDefault,dest);// степень сжатия по умолчанию
if compressRatio=1 then
CompresSstream:=TCompressionStream.Create(clFastest,dest);// самая быстрая степень сжатия
if compressRatio=2 then
CompresSstream:=TCompressionStream.Create(clMax,dest);// самая высокая степнь сжатия
if compressRatio>2 then
CompresSstream:=TCompressionStream.Create(clDefault,dest);
interval:=max_value-min_value; // узнаём интервал в ” делениях ”
if source.Size<>0 then
zena _ byta := interval / source . Size // zena _ byta = сколько байтов надо считать чтобы прибавилось
//одно “деление”
Else
zena_byta:=interval; // воизбежание оБшибок
Bytes_read_d:=0; // она будет хранить общее количество байт, которое мы считали:
// обнуляем её
if progress<>nil then needProgress:=true; //если указатель прогресс есть, то будем отображать
// архивацию .
if needprogress then
begin
{
Теперь настало время рассказать о супер-фишке которой нет и никогда не будет в С++ чисто по своему определению!!!!
procedure SetPropValue(Instance: TObject; const PropName: string; const Value: Variant);
Присваивает свойству PropName заданное как СТРОКА!!! у объекта Instance значение Value которое может, быть ЛЮБОГО типа (integer, real, string, array и т.д. и т.п.)
Эта процедура использует RTTI информацию объектов и очень сильно загромождает программу и советую её использовать, только если по другому нельзя!!
Кстати, тип Variant – это тоже ВЕЛИКОЕ достижение компании Borland.
И несколько слов про C++ Builder. По определению: откомпилированный экзешник языка С очень сильно отличается от Pascal’евского, поэтому С остаётся С даже если он от Borland}
SetPropValue(TObject(progress^),’Progress’,min_value); // устанавливаем прогресс в начало
end;
try
repeat // пошёл тот самый процесс
bytesread:=source.Read(mainbuffer,buffer_size);
CompresSstream.Write(mainbuffer,bytesread);
Bytes_read_d:=bytes_read_d+bytesread; // обновляем переменную
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 (это самое оптимальное значение – проверено опытом!!!).
function ZLATdecompressfile;
var
source,dest:TFileStream;
decompressStream:TDecompressionStream;
bytesread:integer;
bytesread_d:int64;
interval:integer;
zena_byta:real;
mainbuffer:array[0..buffer_size-1] of char;
needProgress:boolean;
begin
needprogress:=false;
source:=TFileStream.Create(sourcefile,fmOpenRead);
if needcreate then
dest:=TFileStream.Create(destinationfile,fmCreate)
else
dest:=TFileStream.Create(destinationfile,fmOpenWrite);
decompressStream:=TDecompressionStream.Create(source);
result:=true; // результат – это успешность проделанной нами операции
interval:=max_value-min_value;
zena_byta:=interval/source.Size;
bytesread_d:=0;
if progress<>nil then needProgress:=true;
if needprogress then
begin
SetPropValue(TObject (progress^), PositionPropName,min_value);
end;
try
repeat
bytesread:=decompressStream.Read(mainbuffer,buffer_size);
dest.Write(mainbuffer,bytesread);
bytesread_d:=bytesread_d+bytesread;
if refreshWnd then
Application.ProcessMessages;
if needprogress then
begin
if bytesread_d>source.Size then // самое интересное !!!
begin // смотрим: если всего считано байт больше чем размер сжатого
zena_byta:=interval/bytesread_d; // то перерасчитываем переменную zena_byta
end;
SetPropValue(TObject(progress^), PositionPropName,min_value+round(bytesread_d*zena_byta));
end;
until bytesread<buffer_size;
except //провал
result:=false; // результат = НЕТ
decompressStream.Free;
source.Free;
dest.Free;
exit;
end;
decompressStream.Free;
source.Free;
dest.Free;
end;
Итак, теперь нам надо скопировать файл ZLibAdvTools.pas в папку Lib в корневой папке Delphi и подключить этот модуль в любом месте программы: Uses ZLibAdvTools;
На сегодня пожалуй всё.
Это моя первая статья, пожалуйста, оценивайте.
Скачать модуль архивации (13 кб)
Автор статьи
Похожие статьи
Купить рекламу на сайте за 1000 руб
пишите сюда - alarforum@yandex.ru
Да и по любым другим вопросам пишите на почту
пеллетные котлы
Пеллетный котел Emtas
Наши форумы по программированию:
- Форум Web программирование (веб)
- Delphi форумы
- Форумы C (Си)
- Форум .NET Frameworks (точка нет фреймворки)
- Форум Java (джава)
- Форум низкоуровневое программирование
- Форум VBA (вба)
- Форум OpenGL
- Форум DirectX
- Форум CAD проектирование
- Форум по операционным системам
- Форум Software (Софт)
- Форум Hardware (Компьютерное железо)