Sign in Join
Wiki copytemporary

paszlib/ru: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: paszlib/ru

OldNewLine
1+**paszlib** представляет собой преобразование стандартной библиотеки zlib на Паскаль: вам не нужны никакие внешние зависимости. Его реализовал Jacques Nomssi Nzali (его старая домашняя страница мертва, см. продолжение проекта [здесь](http://sageshome.net/oss/paszlib-sg.php)). Он используется в FCL для реализации класса TCompressionStream.
2+
3+Этот класс позволяет сжимать и распаковывать файлы **.zip**.
4+
5+Основной модуль этого пакета - **paszlib**. Существуют и другие вспомогательные модули, но единственный модуль, который необходимо включить в типичную программу, - этот.
6+
7+# TZipper
8+
9+TZipper поддерживает сжатие и распаковку файлов .zip, но не поддерживает все методы сжатия zip.
10+
11+## Документация
12+
13+См. [официальную документацию FPC для Zipper](http://www.freepascal.org/docs-html/fcl/zipper/index.html)
14+
15+## Примеры
16+
17+### Упаковка файлов
18+
19+Создание zip-файла с именем в качестве первого параметра. Все остальные параметры обрабатываются как имена файлов для добавления, поэтому вы можете указать, например,
20+
21+```dos
22+zipper newzip.zip autoexec.bat config.sys
23+```
24+
25+``` pascal
26+uses
27+ Zipper;
28+var
29+ OurZipper: TZipper;
30+ I: Integer;
31+begin
32+ OurZipper := TZipper.Create;
33+ try
34+ // Опредяем имя создаваемого zip-файла.
35+ OurZipper.FileName := ParamStr(1);
36+ for I := 2 to ParamCount do
37+ // В качестве первого аргумента указываем имена файлов, которые будут включены в zip-архив.
38+ // Второй аргумент - это имя файла в том виде, в котором оно отображается в zip-архиве, и
39+ // позже в файловой системе после распаковки
40+ OurZipper.Entries.AddFileEntry(ParamStr(I), ParamStr(I));
41+ // Выполняем операцию архивирования и записываем архивный файл.
42+ OurZipper.ZipAllFiles;
43+ finally
44+ OurZipper.Free;
45+ end;
46+end.
47+```
48+
49+Обратите внимание, что имена архивируемых файлов должны содержать только символы из старого набора символов IBM PC (кодовая страница 437). Расширенные символы (UTF-8) см. в разделе ниже.
50+
51+### Распаковка файлов
52+
53+Распаковываем все файлы из архива c:\test.zip в папку c:\windows\temp\\
54+
55+``` pascal
56+uses
57+ Zipper;
58+var
59+ UnZipper: TUnZipper;
60+begin
61+ UnZipper := TUnZipper.Create;
62+ try
63+ UnZipper.FileName := 'c:\test.zip';
64+ UnZipper.OutputPath := 'c:\windows\temp';
65+ UnZipper.Examine;
66+ UnZipper.UnZipAllFiles;
67+ finally
68+ UnZipper.Free;
69+ end;
70+end.
71+```
72+
73+### Упаковка файлов с сохранением кодировки имен файлов
74+
75+Как уже отмечалось, формат файла zip изначально был написан для поддержки только кодовой страницы 437 IBM PC. Однако в современных операционных системах кодировка имен файлов является гораздо более общей.
76+
77+Если у вас версия **FPC 3.2 или новее**, вы можете воспользоваться логическим свойством `UseLanguageEncoding`. Если установлено значение `true`, предполагается, что имена файлов имеют кодировку по умолчанию FPC, в случае программ Lazarus это UTF-8. Здесь в zipper можно передать любое имя файла (за исключением, конечно, ограничений ОС).
78+
79+В следующей практической программе для FPC 3.2 из файлов в заданном каталоге создается zip-файл, чтобы имена файлов считались правильными:
80+
81+``` pascal
82+uses
83+ FileUtil, zipper;
84+
85+function PackFiles(AZipFilename, ADirectory, AMask: String;
86+ IncludingSubDirs: Boolean): Boolean;
87+var
88+ OurZipper: TZipper;
89+ list: TStringList;
90+ i: Integer;
91+ diskFileName, archiveFileName: String;
92+begin
93+ Result := false;
94+ ADirectory := IncludeTrailingPathDelimiter(ADirectory);
95+ if DirectoryExists(ADirectory) then
96+ begin
97+ OurZipper := TZipper.Create;
98+ try
99+ // Задаем имя создаваемого zip-файла
100+ OurZipper.FileName := AZipFileName;
101+
102+ // Считываем имена файлов, содержащихся в ADirectory, в stringlist
103+ list := TStringList.Create;
104+ try
105+ // FindAllFiles добавляет все имена файлов, соответствующие маске (например, '*.*'),
106+ // найденных в указанном каталоге в предоставленный список.
107+ // Если IncludingSubDirs - true, поиск продолжается рекурсивно и в
108+ // подкаталогах.
109+ FindAllFiles(list, ADirectory, AMask, IncludingSubDirs);
110+ for i := 0 to list.Count - 1 do
111+ begin
112+ // diskfilename - это имя файла, который будет заархивирован на диске
113+ diskFileName := list[i];
114+ // archivefilename - это имя файла, который нужно заархивировать, как он выглядит
115+ // в zip. Убираем директорию из
116+ archiveFileName := StringReplace(diskFileName, ADirectory, '', []);
117+ // Сохраняем эти файлы для архиватора
118+ OurZipper.Entries.AddFileEntry(diskFileName, archiveFileName);
119+ end;
120+ finally
121+ list.Free;
122+ end;
123+ // По умолчанию архиватор записывает имена файлов в кодировке IBM PC CP437.
124+ // Кодировка UTF8 записывается, когда UseLanguageEncoding - true.
125+ OurZipper.UseLanguageEncoding := true; // Требуется FPC 3.2+
126+ // создаем и записываем zip-файл
127+ OurZipper.ZipAllFiles;
128+ Result := true;
129+ finally
130+ OurZipper.Free;
131+ end;
132+ end else
133+ Result := false;
134+end;
135+```
136+
137+Если у вас версия **FPC меньше v3.2**, вы должны преобразовать аргумент ArchiveFileName в CP437 - конечно, это возможно не для всех символов, и поэтому вы должны быть очень осторожны с архиватором в этом случае. Также обратите внимание, что `DiskFileName` должен иметь кодировку, требуемую операционной системой, иначе файл для архивирования не будет найден; в случае FPC до 3.0 может потребоваться еще одно преобразование кодовой страницы.
138+
139+Вот адаптация приведенного выше примера для версии FPC до 3.2:
140+
141+``` pascal
142+uses
143+ FileUtil, LConvEncoding, LazUTF8, Zipper;
144+
145+function PackFiles(AZipFilename, ADirectory, AMask: String;
146+ IncludingSubdirs: Boolean): Boolean;
147+var
148+ OurZipper: TZipper;
149+ list: TStringList;
150+ i: Integer;
151+ diskFileName, archiveFileName: String;
152+begin
153+ Result := false;
154+ if AMask = '' then AMask := '*.*';
155+ ADirectory := IncludeTrailingPathDelimiter(ADirectory);
156+ if DirectoryExists(ADirectory) then
157+ begin
158+ OurZipper := TZipper.Create;
159+ try
160+ OurZipper.FileName := AZipFileName;
161+ list := TStringList.Create;
162+ try
163+ // Перечислияем все файлы в ADirectory и, если необходимо, его подкаталоги.
164+ FindAllFiles(list, ADirectory, AMask, IncludingSubDirs);
165+ for i := 0 to list.Count-1 do
166+ begin
167+ // Имя файла, который нужно заархивировать на диске
168+ diskFileName := list[i];
169+ {$IF FPC_FullVersion < 30000}
170+ diskFileName := UTF8ToWinCP(diskFileName);
171+ {$IFEND}
172+ // Имя файла, который нужно заархивировать в архиве: убираем
173+ // общий путь и таким образом обозначаем файлы относительно каталога
174+ // в который они будут распакованы позже.
175+ archiveFileName := StringReplace(list[i], ADirectory, '', []);
176+ archiveFileName := UTF8ToCP437(archiveFileName);
177+ OurZipper.Entries.AddFileEntry(diskFileName, archiveFileName);
178+ end;
179+ finally
180+ list.Free;
181+ end;
182+ // Выполняем действие архивирования и создаем архивный файл.
183+ OurZipper.ZipAllFiles;
184+ Result := true;
185+ finally
186+ OurZipper.Free;
187+ end;
188+ end;
189+end;
190+```
191+
192+Еще одно ограничение - это разделитель пути в имени заархивированного файла. Спецификация формата zip требует, чтобы косая черта (слэш) ('`/`') использовалась даже в случае Windows. Это важно для однопараметрической перегрузки `TZipper.Entries.AddFileEntry(DiskfileName)`, которая просто предполагает, что имя заархивированного файла равно `DiskFileName`, без каких-либо адаптаций. Следовательно, такой zip-файл будет содержать обратный слэш в Windows. Он будет правильно распакован в Windows, но не в Linux, где обратный слэш считается допустимым символом имени файла. Настоятельно рекомендуется использовать двухпараметрическую версию `TZipper.Entries.AFileEntry(DiskFileName, ArchiveFileName)` с `ArchivefileName = DiskFileName`, поскольку эта процедура автоматически заменяет разделители путей по мере необходимости.
193+
194+### Распаковка файлов с сохранением кодировки имен
195+
196+``` pascal
197+uses
198+ Zipper, LConvEncoding;
199+...
200+function EndPathCP866ToUTF8(AText:string):string;
201+var
202+ c,i:integer;
203+ s,s1,s2,chr:string;
204+begin
205+ s:='';
206+ c:=UTF8Length(AText);
207+ for i:=c downto 1 do
208+ begin
209+ chr:=UTF8Copy(AText,i,1);
210+ if ((not(chr='/')) and (not(chr='\')))or(i=c) then
211+ begin
212+ s:=UTF8Copy(AText,i,1)+s;
213+ end
214+ else begin
215+ s:=UTF8Copy(AText,i,1)+s;
216+ break;
217+ end;
218+ end;
219+ dec(i);
220+ s1:=UTF8Copy(AText,1,i);
221+ s2:=CP866ToUTF8(s);
222+ Result:=s1+s2;
223+end;
224+
225+function UnPackFiles(Filename, UnPackPath: String): Integer;
226+var
227+ UnZipper :TUnZipper; //PasZLib
228+ UnPackFileDir,
229+ ADiskFileName,
230+ ANewDiskFileName,
231+ AArchiveFileName :String;
232+ i :integer;
233+begin
234+ Result:=-1;
235+ if FileExists(Filename)and DirectoryExists(UnPackPath) then
236+ begin
237+ UnPackFileDir :=SysUtils.IncludeTrailingPathDelimiter(UnPackPath);
238+ UnZipper :=TUnZipper.Create;
239+ try
240+ UnZipper.FileName := Filename;
241+ UnZipper.OutputPath := UnPackPath;
242+ UnZipper.Examine;
243+ UnZipper.UnZipAllFiles;
244+
245+ for i:=UnZipper.Entries.Count-1 downto 0 do
246+ begin
247+ AArchiveFileName:=UnZipper.Entries.Entries[i].ArchiveFileName;
248+ AArchiveFileName:=EndPathCP866ToUTF8(AArchiveFileName);
249+ AArchiveFileName:=UTF8ToSys(AArchiveFileName);
250+ ANewDiskFileName:=UnPackFileDir+AArchiveFileName;
251+ ADiskFileName :=UnPackFileDir+UnZipper.Entries.Entries[i].DiskFileName;
252+
253+ if FileExists(ADiskFileName) then
254+ begin
255+ RenameFile(ADiskFileName, ANewDiskFileName);
256+ end
257+ else if DirectoryExists(ADiskFileName) then
258+ begin
259+ ADiskFileName :=SysUtils.IncludeTrailingPathDelimiter(ADiskFileName);
260+ ANewDiskFileName :=SysUtils.IncludeTrailingPathDelimiter(ANewDiskFileName);
261+ RenameFile(ADiskFileName, ANewDiskFileName);
262+ end;
263+ end;
264+
265+ Result:=1;
266+ finally
267+ UnZipper.Free;
268+ end;
269+ end;
270+end;
271+```
272+
273+Дополнительные примеры можно найти в исходном каталоге FPC:
274+
275+- примеры: [1](http://svn.freepascal.org/svn/fpc/trunk/packages/paszlib/examples/)
276+- тестовые программы: [2](http://svn.freepascal.org/svn/fpc/trunk/packages/paszlib/tests)
277+
278+### Распаковка файла в поток (память)
279+
280+В Lazarus поместите в форму TMemo, TButton, TEdit и TFileNameEdit. Нажатие кнопки приведет к чтению zip-файла в FileNameEdit, извлечению файла, указанному в поле Edit, и отображению содержимого в Memo.
281+
282+``` pascal
283+uses
284+ Zipper;
285+
286+...
287+
288+procedure TForm1.Button1Click(Sender: TObject);
289+begin
290+ ExtractFileFromZip(FileNameEdit1.FileName,Edit1.Text);
291+end;
292+
293+procedure TForm1.DoCreateOutZipStream(Sender: TObject; var AStream: TStream;
294+ AItem: TFullZipFileEntry);
295+begin
296+ AStream:=TMemorystream.Create;
297+end;
298+
299+procedure TForm1.DoDoneOutZipStream(Sender: TObject; var AStream: TStream;
300+ AItem: TFullZipFileEntry);
301+begin
302+ AStream.Position:=0;
303+ Memo1.lines.LoadFromStream(Astream);
304+ Astream.Free;
305+end;
306+
307+procedure TForm1.ExtractFileFromZip(ZipName, FileName: string);
308+var
309+ ZipFile: TUnZipper;
310+ sl:TStringList;
311+begin
312+ sl:=TStringList.Create;
313+ sl.Add(FileName);
314+ ZipFile := TUnZipper.Create;
315+ try
316+ ZipFile.FileName := ZipName;
317+ ZipFile.OnCreateStream := @DoCreateOutZipStream;
318+ ZipFile.OnDoneStream:=@DoDoneOutZipStream;
319+ ZipFile.UnZipFiles(sl);
320+ finally
321+ ZipFile.Free;
322+ sl.Free;
323+ end;
324+end;
325+```
326+
327+### Архивирование всего дерева каталогов
328+
329+- Этот пример рекурсивно добавит содержимое 'C: MyFolder' в 'myzipfile.zip'
330+ - Обратите внимание, что в zip-файле абсолютный путь сохраняется.
331+ - Обратите внимание, что для этого требуется модуль Lazarus fileutil (который, вероятно, можно обойти)
332+
333+``` pascal
334+Uses ...Zipper,FileUtil
335+var
336+ AZipper: TZipper;
337+ TheFileList:TStringList;
338+begin
339+ MyDirectory:='C:\MyFolder';
340+ AZipper := TZipper.Create;
341+ AZipper.Filename := 'myzipfile.zip';
342+ TheFileList:=TStringList.Create;
343+ try
344+ FindAllFiles(TheFileList, MyDirectory);
345+ AZipper.Entries.AddFileEntries(TheFileList);
346+ AZipper.ZipAllFiles;
347+ finally
348+ TheFileList.Free;
349+ AZipper.Free;
350+ end;
351+end;
352+```
353+
354+### Архивирование всего дерева каталогов с сохранением только относительного пути
355+
356+- Это сложнее, но это можно сделать
357+ - Обратите внимание, что для этого требуется модуль Lazarus fileutil (который, вероятно, можно обойти)
358+
359+``` pascal
360+Uses ...Zipper,FileUtil,strutils
361+var
362+ AZipper: TZipper;
363+ szPathEntry:String;
364+ i:Integer;
365+ ZEntries : TZipFileEntries;
366+ TheFileList:TStringList;
367+ RelativeDirectory:String;
368+begin
369+ AZipper := TZipper.Create;
370+ try
371+ try
372+ AZipper.Filename := 'myzipfile.zip';
373+ RelativeDirectory:='C:\MyFolder\MyFolder\';
374+ AZipper.Clear;
375+ ZEntries := TZipFileEntries.Create(TZipFileEntry);
376+ // Проверяем существование каталога
377+ If DirPathExists(RelativeDirectory) then
378+ begin
379+ // Создаем путь к каталогу НИЖЕ RelativeDirectory.
380+ // Если пользователь указал 'C:\MyFolder\Subfolder' это вернет 'C:\MyFolder\'
381+ // Если пользователь указал 'C:\MyFolder' это вернет 'C:\'
382+ // Если пользователь указал 'C:\' это вернет 'C:\'
383+ i:=RPos(PathDelim,ChompPathDelim(RelativeDirectory));
384+ szPathEntry:=LeftStr(RelativeDirectory,i);
385+
386+ // Используйте функцию FileUtils.FindAllFiles для рекурсивного получения всего (файлов и папок)
387+ TheFileList:=TstringList.Create;
388+ try
389+ FindAllFiles(TheFileList, RelativeDirectory);
390+ for i:=0 to TheFileList.Count -1 do
391+ begin
392+ // Убедитесь, что файлы RelativeDirectory не находятся в корне ZipFile.
393+ ZEntries.AddFileEntry(TheFileList[i],CreateRelativePath(TheFileList[i],szPathEntry));
394+ end;
395+ finally
396+ TheFileList.Free;
397+ end;
398+ end;
399+ if (ZEntries.Count > 0) then
400+ AZipper.ZipFiles(ZEntries);
401+ except
402+ On E: EZipError do
403+ E.CreateFmt('Zip-файл %s не может быть создан по причине %s:', [LineEnding, E.Message])
404+ end;
405+ result := True;
406+ finally
407+ FreeAndNil(ZEntries);
408+ AZipper.Free;
409+ end;
410+end;
411+```
412+
413+Обратите внимание, что в этом примере используется перегруженная версия addfileentry() (по сравнению с простыми примерами). Эта версия позволяет вам указать структуру каталогов внутри Zip-файла, а затем, конечно же, структуру каталогов после его распаковки. Вы можете, например, указать только имя файла без структуры каталогов, и все файлы будут возвращены в одном плоском выходном каталоге. Даже если они собраны отовсюду!
414+
415+``` pascal
416+ZEntries.AddFileEntry(FullDiskPathToFile, FileName);
417+```
418+
419+## См. также
420+
421+- [официальная документация FPC для Zipper](http://www.freepascal.org/docs-html/fcl/zipper/index.html)
422+- [Статья](http://www.freepascal.org/~michael/articles/archives/archives.pdf) демонстрация обработки файлов tar, bzip2, gzip, zip и шифрования Blowfish в FreePascal / Lazarus. Хорошее введение, хотя оно было написано некоторое время назад (улучшена большая часть функциональности).
423+- [[unzip]]
424+- [[FreePascalArchivePackage]] архиватор/zip-библиотека Abbrevia
425+- [MIT licensed Delphi/Object Pascal library](http://code.google.com/p/kstools/) that includes zip file support.
426+
427+Назад к [[Package List|Packages List]]
428+
429+---
430+*From the Free Pascal wiki, page "paszlib/ru", as it stood on 2021-06-08 after a change by Zoltanleo, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
431+Category: FPC
432+Category: Lazarus
433+Category: Packages
434+Category: Tutorials

Back to history