📄 scizipfile.pas
字号:
unit SciZipFile;
// Copyright 2004 Patrik Spanel
// scilib@sendme.cz
// Written from scratch using InfoZip PKZip file specification application note
// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
// uses the Borland out of the box zlib
// Nick Naimo <nick@naimo.com> added support for folders on 6/29/2004 (see "NJN")
// Marcin Wojda <Marcin@sacer.com.pl> added exceptions and try finally blocks
interface
uses SysUtils, Classes, Types, zlib, Windows;
type
TCommonFileHeader = packed record
VersionNeededToExtract: WORD; // 2 bytes
GeneralPurposeBitFlag: WORD; // 2 bytes
CompressionMethod: WORD; // 2 bytes
LastModFileTimeDate: DWORD; // 4 bytes
Crc32: DWORD; // 4 bytes
CompressedSize: DWORD; // 4 bytes
UncompressedSize: DWORD; // 4 bytes
FilenameLength: WORD; // 2 bytes
ExtraFieldLength: WORD; // 2 bytes
end;
TLocalFile = packed record
LocalFileHeaderSignature: DWORD; // 4 bytes (0x04034b50)
CommonFileHeader: TCommonFileHeader; //
filename: AnsiString; //variable size
extrafield: AnsiString; //variable size
CompressedData: AnsiString; //variable size
end;
TFileHeader = packed record
CentralFileHeaderSignature: DWORD; // 4 bytes (0x02014b50)
VersionMadeBy: WORD; // 2 bytes
CommonFileHeader: TCommonFileHeader; //
FileCommentLength: WORD; // 2 bytes
DiskNumberStart: WORD; // 2 bytes
InternalFileAttributes: WORD; // 2 bytes
ExternalFileAttributes: DWORD; // 4 bytes
RelativeOffsetOfLocalHeader: DWORD; // 4 bytes
filename: AnsiString; //variable size
extrafield: AnsiString; //variable size
fileComment: AnsiString; //variable size
end;
TEndOfCentralDir = packed record
EndOfCentralDirSignature: DWORD; // 4 bytes (0x06054b50)
NumberOfThisDisk: WORD; // 2 bytes
NumberOfTheDiskWithTheStart: WORD; // 2 bytes
TotalNumberOfEntriesOnThisDisk: WORD; // 2 bytes
TotalNumberOfEntries: WORD; // 2 bytes
SizeOfTheCentralDirectory: DWORD; // 4 bytes
OffsetOfStartOfCentralDirectory: DWORD; // 4 bytes
ZipfileCommentLength: WORD; // 2 bytes
end;
TZipFile = class(TObject)
Files: array of TLocalFile;
CentralDirectory: array of TFileHeader;
EndOfCentralDirectory: TEndOfCentralDir;
ZipFileComment: string;
private
function GetUncompressed(i: integer): string;
procedure SetUncompressed(i: integer; const Value: string);
function GetDateTime(i: integer): TDateTime;
procedure SetDateTime(i: integer; const Value: TDateTime);
function GetCount: integer;
function GetName(i: integer): string;
procedure SetName(i: integer; const Value: string);
public
property Count:integer read GetCount;
procedure AddFile(const name: string; FAttribute: DWord=0);
procedure SaveToFile(const filename: string);
procedure LoadFromFile(const filename: string);
property Uncompressed[i: integer]: string read GetUncompressed write
SetUncompressed;
property Data[i: integer]: string read GetUncompressed write
SetUncompressed;
property DateTime[i: integer]: TDateTime read GetDateTime write SetDateTime;
property Name[i: integer]:string read GetName write SetName;
end;
EZipFileCRCError = class(Exception);
function ZipCRC32(const Data:string): longword;
implementation
{ TZipFile }
procedure TZipFile.SaveToFile(const filename: string);
var
ZipFileStream: TFileStream;
i: integer;
begin
ZipFileStream := TFileStream.Create(filename, fmCreate);
try
for i := 0 to High(Files) do
with Files[i] do
begin
CentralDirectory[i].RelativeOffsetOfLocalHeader :=
ZipFileStream.Position;
ZipFileStream.Write(LocalFileHeaderSignature, 4);
if (LocalFileHeaderSignature = ($04034B50)) then
begin
//写入文件头
ZipFileStream.Write(CommonFileHeader, SizeOf(CommonFileHeader));
//文件名
ZipFileStream.Write(PChar(filename)^,
CommonFileHeader.FilenameLength);
ZipFileStream.Write(PChar(extrafield)^,
CommonFileHeader.ExtraFieldLength);
//压缩后的数据
ZipFileStream.Write(PChar(CompressedData)^,
CommonFileHeader.CompressedSize);
end;
end;
EndOfCentralDirectory.OffsetOfStartOfCentralDirectory :=
ZipFileStream.Position;
for i := 0 to High(CentralDirectory) do
with CentralDirectory[i] do
begin
ZipFileStream.Write(CentralFileHeaderSignature, 4);
ZipFileStream.Write(VersionMadeBy, 2);
ZipFileStream.Write(CommonFileHeader, SizeOf(CommonFileHeader));
ZipFileStream.Write(FileCommentLength, 2);
ZipFileStream.Write(DiskNumberStart, 2);
ZipFileStream.Write(InternalFileAttributes, 2);
ZipFileStream.Write(ExternalFileAttributes, 4);
ZipFileStream.Write(RelativeOffsetOfLocalHeader, 4);
ZipFileStream.Write(PChar(filename)^, length(filename));
ZipFileStream.Write(PChar(extrafield)^, length(extrafield));
ZipFileStream.Write(PChar(fileComment)^, length(fileComment));
end;
with EndOfCentralDirectory do
begin
EndOfCentralDirSignature := $06054B50;
NumberOfThisDisk := 0;
NumberOfTheDiskWithTheStart := 0;
TotalNumberOfEntriesOnThisDisk := High(Files) + 1;
TotalNumberOfEntries := High(Files) + 1;
SizeOfTheCentralDirectory :=
ZipFileStream.Position - OffsetOfStartOfCentralDirectory;
ZipfileCommentLength := length(ZipFileComment);
end;
ZipFileStream.Write(EndOfCentralDirectory, SizeOf(EndOfCentralDirectory));
ZipFileStream.Write(PChar(ZipFileComment)^, length(ZipFileComment));
finally
ZipFileStream.Free;
end;
end;
procedure TZipFile.LoadFromFile(const filename: string);
var
ZipFileStream: TFileStream;
n: integer;
signature: DWORD;
begin
ZipFileStream := TFileStream.Create(filename, fmOpenRead or fmShareDenyWrite);
n := 0;
try
repeat
signature := 0;
ZipFileStream.Read(signature, 4);
until signature = $04034B50;
repeat
begin
if (signature = $04034B50) then
begin
inc(n);
SetLength(Files, n);
SetLength(CentralDirectory, n);
with Files[n - 1] do
begin
LocalFileHeaderSignature := signature;
ZipFileStream.Read(CommonFileHeader, SizeOf(CommonFileHeader));
SetLength(filename, CommonFileHeader.FilenameLength);
ZipFileStream.Read(PChar(filename)^,
CommonFileHeader.FilenameLength);
SetLength(extrafield, CommonFileHeader.ExtraFieldLength);
ZipFileStream.Read(PChar(extrafield)^,
CommonFileHeader.ExtraFieldLength);
SetLength(CompressedData, CommonFileHeader.CompressedSize);
ZipFileStream.Read(PChar(CompressedData)^,
CommonFileHeader.CompressedSize);
end;
end;
end;
signature := 0;
ZipFileStream.Read(signature, 4);
until signature <> ($04034B50);
n := 0;
repeat
begin
if (signature = $02014B50) then
begin
inc(n);
with CentralDirectory[n - 1] do
begin
CentralFileHeaderSignature := signature;
ZipFileStream.Read(VersionMadeBy, 2);
ZipFileStream.Read(CommonFileHeader, SizeOf(CommonFileHeader));
ZipFileStream.Read(FileCommentLength, 2);
ZipFileStream.Read(DiskNumberStart, 2);
ZipFileStream.Read(InternalFileAttributes, 2);
ZipFileStream.Read(ExternalFileAttributes, 4);
ZipFileStream.Read(RelativeOffsetOfLocalHeader, 4);
SetLength(filename, CommonFileHeader.FilenameLength);
ZipFileStream.Read(PChar(filename)^,
CommonFileHeader.FilenameLength);
SetLength(extrafield, CommonFileHeader.ExtraFieldLength);
ZipFileStream.Read(PChar(extrafield)^,
CommonFileHeader.ExtraFieldLength);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -