Содержание Назад Дальше
Копирование (продолжение) и сжатие
Существует такая штука, как сжатие данных. Хорошо, если вы
инсталлируете свою программу с компакт-диска. Как правило, в такой ситуации вы
не знаете, что ещё записать на эту бездонную болванку и несколько лишних
мегабайт вам в данной ситуации совсем не помешают :)
Совершенно по другому обстоят дела с дискетами. На дискеты надо помещать
сжатую информацию в этом случае вся ваша программа возможно
(только возможно) влезет всего лишь на тридцать четыре дискеты. Вот как
делать сжатие это вопрос.
Я расскажу вам о нескольких методах сжатия данных, которыми вы можете
воспользоваться.
Метод номер раз это сжатие файлов стандартными утилитами,
разработанными фирмой Microsoft. Когда-то это была программа
compress.exe ,
сейчас cabarc.exe.
hInFile := LZOpenFile(PChar(SourcePath), ofInReOpenBuff, OF_READ);
hOutFile := LZOpenFile(PChar(TargetPath), ofOutReOpenBuff, OF_CREATE
or OF_WRITE);
iLZError := LZCopy(hInFile, hOutFile);
if iLZError > 0
then
// Операция выполнилась успешно, скопировано iLZError байт
else
// Ошибка номер iLZError
LZClose(hOutFile);
LZClose(hInFile);
Метод номер два сжатие файлов с помощью библиотеки ZLib, которая
поставляется вместе с Delphi (она находится в каталоге \Info\Extras\ZLib
оригинального диска с Delphi 3.0). Она предоставляет вам два класса, которые
являются наследниками TStream. Вы можете воспользоваться кодом
функции копирования при помощи TFileStream из предыдущей статьи для
того, чтобы реализовать как сжатие, так и распаковку произвольного потока
(в том числе и файла).
Ещё один метод использование динамической
библиотеки unrar.dll, разработанной
Евгением Рошалом. Существуют и другие библиотеки (даже компоненты), вы можете
свободно найти их, если будете достаточно долго шляться по Интернету.
- Примечание:
- Мне кажется, что менее всего размер вашей инсталляции увеличится, если вы
используете методы, предлагаемые Microsoft; ровно потому, что они встроены
в Windows и вам не надо записывать их на дискету.
Копирование нескольких файлов представляется достаточно простым, раз уж
мы научились копировать один файл. Наиболее просто это делается, если ваши
файлы поставляются в одном архиве (
.CAB или
.RAR). Сложным
может показаться копирование файлов по маске (
*.*) и копирование
вложенных подкаталогов. Ниже приводится исходный текст процедуры, которая
составляет список файлов в каталоге и всех вложенных подкаталогах.
procedure ReadTree(Path:
String; Strings: TStrings);
procedure ReadFolder(Path:
String; Strings: TStrings);
var
SearchRec: TSearchRec;
FindResult: Integer;
begin
FindResult := FindFirst(Path + '*.*', faAnyFile, SearchRec);
while FindResult = 0
do
begin
// Если найден подкаталог, рекурсивно читаем его содержимое
// Не забываем игнорировать подкаталоги '.' и '..'
with SearchRec
do
if (Name <> '.')
and (Name <> '..')
then
begin
Strings.Add(Path + Name);
if (Attr
and faDirectory <> 0)
then
ReadFolder(Path + Name + '\', Strings);
end;
FindResult := FindNext(SearchRec);
end;
FindClose(SearchRec);
end;
begin
// Эта процедура заносит в Strings список файлов во всех вложенных папках
// каталога Path и сами эти папки
Strings.Clear;
if (Length(Path) > 0)
and (Path[Length(Path)] <> '\')
then
Path := Path + '\';
ReadFolder(Path, Strings);
end;
Отдельно стоит поговорить о тех файлах, которые могут использоваться сразу
несколькими программами. Для этих файлов существует даже специальное название
разделяемые (поскольку несколько программ делят их
между собой). Обычно они записываются в системный каталог Windows (для
Windows 95 это как правило \WINDOWS\SYSTEM, для Windows NT
\WINNT\SYSTEM32). Если системный каталог доступен только для чтения, то
эти файлы необходимо записывать в каталог Windows (\WINDOWS и \WINNT
соответственно), который всегда доступен для записи.
function GetSysDir:
String;
var
szPath:
array [0..MAX_PATH - 1]
of Char;
I: Integer;
Stream: TStream;
begin
// Получаем системный каталог
GetSystemDirectory(szPath, MAX_PATH);
Result := StrPas(szPath);
// Добавляем обратный слеш в конец пути, если его там нет
if (Length(Result) > 0)
and (Result[Length(Result)] <> '\')
then
Result := Result + '\';
// Подбираем имя файла вида XXXXXXXX.TMP, где XXXXXXXX ---
// шестнадцатиричное число, который не существует в системном каталоге
I := 0;
while FileExists(Result + IntToHex(I, 8) + '.TMP')
do
Inc(I);
try
// Создаём файл и удаляем его. Если всё нормально, то каталог доступен
// для записи.
Stream := TFileStream(Result + IntToHex(I, 8) + '.TMP', fmCreate);
Stream.Free;
DeleteFile(Result + IntToHex(I, 8) + '.TMP');
except
// Если создать файл не удалось, в качестве системного каталога будем
// использовать каталог Windows.
GetWindowsDirectory(szPath, MAX_PATH);
Result := StrPas(szPath);
if (Length(Result) > 0)
and (Result[Length(Result)] <> '\')
then
Result := Result + '\';
end;
end;
Если разделяемый файл уже существует в целевом каталоге, то необходимо
сравнить версии, языки и др. характеристики двух файлов и на основании этого
сравнения решать копировать файл или не надо.
При копировании разделяемых файлов требуется уведомить Windows о том, что
одним разделением стало больше. Это делается через реестр. При замещении
файлов, которые в момент инсталляции используются Windows требуется
определённая техника, поскольку перезаписать занятый файл нельзя.
Эти вопросы в ближайшее время будут освещены в следующей статье. Поистине,
копирование файлов тема неисчерпаемая :)
Напоследок, исследуем вопрос о том, куда копировать файлы? В соответствии
с рекомендациями Microsoft, каталог вашей программы должен иметь форму
<Program Files>\<Название вашей фирмы>\<Название продукта>.
Вы можете также включить в название каталога информацию о версии продукта,
например C:\Program Files\Borland\Delphi 3, хотя возможен и вариант
C:\Program Files\Borland\Delphi\3 (реально фирма Borland использует
первый вариант). Бывают и исключения, в частности FAR Евгения Рошала
ставится в C:\Program Files\FAR.
Разделяемые файлы следует копировать в системный каталог Windows, а если
он защищён от записи в каталог Windows.
А сейчас мы переходим к реестру.
Содержание Назад Дальше