Существует такая штука, как сжатие данных. Хорошо, если вы
инсталлируете свою программу с компакт-диска. Как правило, в такой ситуации вы
не знаете, что ещё записать на эту бездонную болванку и несколько лишних
мегабайт вам в данной ситуации совсем не помешают :)
Совершенно по другому обстоят дела с дискетами. На дискеты надо
помещать сжатую информацию — в этом случае вся ваша программа возможно (только
возможно) влезет всего лишь на тридцать четыре дискеты. Вот как делать сжатие —
это вопрос.
Я расскажу вам о нескольких методах сжатия данных, которыми вы
можете воспользоваться.
Метод номер раз — это сжатие файлов стандартными утилитами,
разработанными фирмой Microsoft. Когда-то это была программа
compress.exe
(9554), сейчас — cabarc.exe
(35703).
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
(27336), разработанной Евгением Рошалом. Существуют и другие библиотеки
(даже компоненты), вы можете свободно найти их, если будете достаточно долго
шляться по Интернету.
- Примечание:
- Мне кажется, что менее всего размер вашей инсталляции увеличится, если вы
используете методы, предлагаемые 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.
А сейчас мы переходим к реестру.
|