按Delphi帮助编写的zlib压缩无效,求可用gzip代码示例
问题原因
Embarcadero的示例代码生成的是原始zlib数据流,不是标准gzip格式。gzip有固定的文件头、CRC校验和原始长度尾段,这些是通用解压工具识别的关键标识;而原始zlib流仅包含压缩数据块,没有这些标准结构,所以只有Delphi自带的zlib工具能识别,其他通用工具(比如7-Zip、WinRAR)无法解析。
标准gzip格式的Delphi代码示例
以下代码基于Delphi自带的ZLib单元实现,无需第三方库,生成的gzip文件可被所有通用解压工具识别:
压缩为gzip格式
uses ZLib, Classes, SysUtils; procedure CompressToGZip(const SourceFile, DestFile: string); var SourceStream, DestStream: TFileStream; CompressStream: TZCompressionStream; GZipHeader: array[0..9] of Byte; CRC: Cardinal; UncompressedSize: Integer; begin if not FileExists(SourceFile) then raise Exception.Create('源文件不存在'); SourceStream := TFileStream.Create(SourceFile, fmOpenRead or fmShareDenyWrite); try DestStream := TFileStream.Create(DestFile, fmCreate or fmShareDenyWrite); try // 写入标准gzip文件头 FillChar(GZipHeader, SizeOf(GZipHeader), 0); GZipHeader[0] := $1F; // gzip标识字节1 GZipHeader[1] := $8B; // gzip标识字节2 GZipHeader[2] := $08; // 压缩方式为DEFLATE GZipHeader[9] := $03; // 操作系统标识(Unix,可改为$00表示FAT/Windows) DestStream.WriteBuffer(GZipHeader, SizeOf(GZipHeader)); // 初始化CRC32校验计算 CRC := crc32(0, nil, 0); UncompressedSize := SourceStream.Size; // 创建压缩流并写入数据 CompressStream := TZCompressionStream.Create(clMax, DestStream); try CRC := crc32(CRC, SourceStream.Memory, SourceStream.Size); CompressStream.CopyFrom(SourceStream, 0); finally CompressStream.Free; end; // 写入CRC校验值和原始文件大小(gzip标准要求) DestStream.WriteBuffer(CRC, SizeOf(CRC)); DestStream.WriteBuffer(UncompressedSize, SizeOf(UncompressedSize)); finally DestStream.Free; end; finally SourceStream.Free; end; end;
解压gzip格式文件
uses ZLib, Classes, SysUtils; procedure DecompressGZip(const SourceFile, DestFile: string); var SourceStream, DestStream: TFileStream; DecompressStream: TZDecompressionStream; GZipHeader: array[0..9] of Byte; CRC, CheckCRC: Cardinal; UncompressedSize, CheckSize: Integer; ReadCount: Integer; Buffer: array[0..4095] of Byte; begin if not FileExists(SourceFile) then raise Exception.Create('gzip源文件不存在'); SourceStream := TFileStream.Create(SourceFile, fmOpenRead or fmShareDenyWrite); try // 读取并验证gzip文件头 SourceStream.ReadBuffer(GZipHeader, SizeOf(GZipHeader)); if (GZipHeader[0] <> $1F) or (GZipHeader[1] <> $8B) or (GZipHeader[2] <> $08) then raise Exception.Create('无效的gzip文件格式'); // 跳过gzip头中的可选字段(简化处理,若需支持完整gzip标准可扩展) if (GZipHeader[3] and $04) <> 0 then // 存在额外字段 begin var ExtraLen: Word; SourceStream.ReadBuffer(ExtraLen, SizeOf(ExtraLen)); SourceStream.Seek(ExtraLen, soCurrent); end; if (GZipHeader[3] and $08) <> 0 then // 存在文件名 while SourceStream.ReadByte <> 0 do; if (GZipHeader[3] and $10) <> 0 then // 存在注释 while SourceStream.ReadByte <> 0 do; // 读取文件末尾的CRC校验值和原始文件大小 SourceStream.Seek(-(SizeOf(CRC) + SizeOf(UncompressedSize)), soEnd); SourceStream.ReadBuffer(CheckCRC, SizeOf(CheckCRC)); SourceStream.ReadBuffer(CheckSize, SizeOf(CheckSize)); SourceStream.Seek(SizeOf(GZipHeader), soBeginning); // 解压数据并校验CRC DestStream := TFileStream.Create(DestFile, fmCreate or fmShareDenyWrite); try DecompressStream := TZDecompressionStream.Create(SourceStream); try CRC := crc32(0, nil, 0); repeat ReadCount := DecompressStream.Read(Buffer, SizeOf(Buffer)); if ReadCount > 0 then begin CRC := crc32(CRC, @Buffer, ReadCount); DestStream.WriteBuffer(Buffer, ReadCount); end; until ReadCount = 0; // 验证CRC和文件大小 if (CRC <> CheckCRC) or (DestStream.Size <> CheckSize) then raise Exception.Create('文件损坏或CRC校验失败'); finally DecompressStream.Free; end; finally DestStream.Free; end; finally SourceStream.Free; end; end;
使用示例
// 压缩 CompressToGZip('C:\test.txt', 'C:\test.txt.gz'); // 解压 DecompressGZip('C:\test.txt.gz', 'C:\test_uncompressed.txt');
内容的提问来源于stack exchange,提问作者Mikael
相关产品推荐
相关产品推荐

