简介:Abbrevia 3.05 是 TurboPower 出品的压缩库,主要面向 Delphi 与 C++Builder 开发者,用于在应用程序中集成 ZIP、LZH、ARJ、TAR、GZIP、BZIP2 等多种格式的压缩与解压能力。资源包共 561 个文件,约 3.61MB,以 pas、dfm、cpp、h、dpr、dpk 等源码与工程文件为主,另有 res、ico 等资源文件及少量 zip、cab 示例包,并附带 MPL-1.1 许可说明与 readme 文档。packages 目录提供不同编译环境的包装文件,source 目录开放完整源代码,examples 目录则给出创建 ZIP、添加与提取文件等典型用法示例,便于理解 API 调用与内部实现。已有 142 人学习关注。对于需要处理跨平台数据交换、批量文件归档或希望定制压缩流程的开发者,这份资料可帮助快速完成库的集成、源码研读与功能扩展,并注意与所用 IDE 版本及目标系统的兼容性。
1. Abbrevia 3.05 拆包实录:Delphi 老项目里那套还能打的压缩库
接手一个维护了七八年的 Delphi 项目,客户突然要求支持 ZIP 和 TAR 双格式导入导出,还得兼容老版本 Windows 上跑。翻遍现有代码,压缩模块用的是系统自带 API,格式支持少得可怜,换第三方库又怕引入一堆依赖。这时候同事甩过来一个压缩包,文件名就一行Abbrevia 3.05_abbrevia_,说这玩意儿当年救过他的命。打开一看,source、packages、examples三个文件夹整整齐齐,add.asp、extract.asp、viewzip.asp、display.asp几个示例页面摆在那,还有一堆.bpk包文件对应不同版本的 Delphi 和 C++Builder。Abbrevia 是 TurboPower 出品的开源压缩库,MPL-1.1 协议,专门给 Delphi 和 C++Builder 环境用,支持 ZIP、LZH、ARJ、TAR、GZIP、BZIP2 这些常见格式。如果你手头有老 Delphi 项目要加压缩功能,又不想从头造轮子,这套源码值得花时间拆一拆。它适合两类人:一是维护遗留系统的工程师,二是想研究 Pascal 压缩算法实现的学习者。下面按我实际拆包的顺序,把关键路径和踩过的坑捋一遍。
2. 源码结构与包文件:先搞清楚哪个 .bpk 对应你的 IDE
拿到一个压缩包,最忌讳上来就双击安装。Abbrevia 3.05 的目录结构不算复杂,但包文件命名有讲究,选错了编译都过不去。先花十分钟把目录摸清楚,后面能省掉大量返工。
2.1 目录布局与核心文件定位
解压后根目录下能看到这些内容:source文件夹放的是全部 Pascal 源码,packages里是按 IDE 版本分好的包文件,examples下是演示程序,另外还有MPL-1_1.txt和readme.txt。readme.txt别跳过,里面写了各包文件对应的 IDE 版本和已知问题,比网上搜的教程靠谱。
source目录里文件数量不少,核心单元包括AbZIP.pas、AbTar.pas、AbGZIP.pas、AbBZip2.pas等,每个格式一个单元。还有一个AbBase.pas是公共基类,定义了压缩流的基本接口。如果你只想用 ZIP,那重点看AbZIP.pas和AbBase.pas就够了;要支持多格式,就把对应的单元都加进项目。
packages目录下的.bpk文件命名规则是B305加后缀。B305_r61.bpk对应 Delphi 6/7 的运行时包,B305cd61.bpk是设计时包,B305vd61.bpk是 C++Builder 6 的包,B305vr61.bpk和B305cr61.bpk分别对应 C++Builder 的运行时和设计时。后缀里的r代表 runtime,c代表 design-time component,v代表 C++Builder 的 VCL 包。搞混了会出现「组件面板里看不到控件」或者「编译时报找不到单元」这类问题。
提示:如果你用的是 Delphi 2007 之后的版本,这些
.bpk文件可能需要手动转换或调整搜索路径,因为 Abbrevia 3.05 发布年代较早,官方包文件主要覆盖到 Delphi 7 和 C++Builder 6。
2.2 包文件选择与编译顺序
选包文件之前先确认你的 IDE 版本。打开 Delphi,菜单 Help → About 看版本号。如果是 Delphi 7,就用B305_r61.bpk和B305cd61.bpk;如果是 C++Builder 6,对应B305vr61.bpk和B305cr61.bpk。编译顺序是先运行时包,再设计时包,反过来会报错。
具体操作步骤:
- 在 Delphi 中打开
packages\B305_r61.bpk,右键点击包节点,选择 Install。这一步会把运行时包编译并注册到系统中。 - 再打开
packages\B305cd61.bpk,同样执行 Install。设计时包安装完成后,组件面板上会出现 Abbrevia 标签页,里面能看到TAbZipper、TAbUnZipper、TAbGZipper等控件。 - 如果编译过程中提示找不到
AbBase或其他单元,检查 IDE 的 Library Path 是否包含了source目录的完整路径。菜单 Tools → Environment Options → Library → Library Path,把source目录加进去。
编译时可能遇到的报错及处理:
File not found: 'AbBase.dcu':搜索路径没配好,把source目录加进 Library Path。Unit 'AbZIP' is compiled with a different version of 'AbBase':之前编译过旧版本,把source目录下所有.dcu文件删掉重新编译。Cannot install package:设计时包依赖运行时包,确认运行时包已经成功编译并安装。
2.3 示例程序的作用与运行方法
examples目录里有几个.asp文件,别被扩展名迷惑,这些不是 Active Server Pages,而是 Abbrevia 示例项目的源文件。add.asp演示如何向 ZIP 文件中添加文件,extract.asp演示解压,viewzip.asp演示查看 ZIP 内容,display.asp可能是辅助显示模块。这些示例用 Delphi 打开后可以直接编译运行,是理解 API 用法最快的途径。
我一般会先编译viewzip.asp对应的项目,因为它不涉及写操作,跑起来就能看到 ZIP 文件里的条目列表,能快速验证库是否正常工作。确认没问题后再看add.asp和extract.asp,这两个涉及文件读写,需要留意路径权限问题。
AllExamples.bpg是一个项目组文件,用 Delphi 打开它会一次性加载所有示例项目。如果你只想快速浏览,用这个文件比较方便;如果要逐个调试,还是单独打开对应的.dpr文件更清晰。
3. 核心 API 与压缩流程:从 TAbZipper 到多格式适配
包安装好之后,下一步就是搞清楚怎么在代码里调用。Abbrevia 的 API 设计偏底层,但封装程度够用,熟悉之后写起来不啰嗦。这一章按「创建压缩包 → 添加文件 → 解压 → 多格式切换」的顺序,把关键类和参数说明白。
3.1 TAbZipper 与 TAbUnZipper 的基本用法
TAbZipper是创建和写入 ZIP 文件的核心类,TAbUnZipper负责读取和解压。这两个类都在AbZIP.pas单元里定义。基本流程是:创建实例 → 设置文件名 → 添加或提取 → 释放。
下面是一段创建 ZIP 并添加文件的代码:
uses AbZIP, AbBase, AbUtils; procedure CreateZipArchive(const ZipFileName, SourceDir: string); var Zipper: TAbZipper; FileList: TStringList; I: Integer; begin Zipper := TAbZipper.Create(nil); try // 设置输出 ZIP 文件路径 Zipper.FileName := ZipFileName; // 设置压缩级别,0-9,9 为最高压缩比 Zipper.CompressionLevel := 9; // 设置临时目录,处理大文件时会用到 Zipper.TempDirectory := ExtractFilePath(ZipFileName) + 'temp\'; FileList := TStringList.Create; try // 收集源目录下所有文件 BuildFileList(SourceDir, FileList); for I := 0 to FileList.Count - 1 do begin // 添加文件到压缩包,第二个参数是包内路径 Zipper.AddFiles(FileList[I], ExtractFileName(FileList[I])); end; finally FileList.Free; end; // 保存压缩包 Zipper.Save; finally Zipper.Free; end; end;逻辑说明:TAbZipper.Create(nil)创建实例,参数是 Owner,传 nil 表示手动管理生命周期。FileName指定输出路径,CompressionLevel控制压缩比,值越大压缩越慢但文件越小。AddFiles方法有两个参数,第一个是磁盘上的源文件路径,第二个是压缩包内的存储路径。Save方法执行实际的写入操作,不调用它压缩包不会生成。
参数说明:CompressionLevel的取值范围通常是 0 到 9,0 表示不压缩只打包,9 表示最大压缩。TempDirectory在处理大文件时会被用来存放临时数据,建议指向一个有足够空间的目录。AddFiles的第二个参数如果传空字符串,默认使用源文件名。
解压的代码类似:
procedure ExtractZipArchive(const ZipFileName, TargetDir: string); var UnZipper: TAbUnZipper; begin UnZipper := TAbUnZipper.Create(nil); try UnZipper.FileName := ZipFileName; // 设置解压目标目录 UnZipper.BaseDirectory := TargetDir; // 提取所有文件 UnZipper.ExtractFiles('*.*'); finally UnZipper.Free; end; end;BaseDirectory指定解压目标目录,ExtractFiles的参数是文件掩码,*.*表示提取全部。如果只想提取特定文件,可以传*.txt这样的模式。
3.2 多格式支持与 TAbArchive 抽象层
Abbrevia 支持 ZIP、TAR、GZIP、BZIP2 等多种格式,每种格式对应一个具体的类,但它们都继承自TAbArchive基类。这意味着你可以用统一的方式处理不同格式,只需要在创建时选择对应的类。
常见格式与对应类的关系:
| 格式 | 核心类 | 所在单元 |
|---|---|---|
| ZIP | TAbZipper / TAbUnZipper | AbZIP.pas |
| TAR | TAbTarArchive | AbTar.pas |
| GZIP | TAbGZipper / TAbGUnZipper | AbGZIP.pas |
| BZIP2 | TAbBZip2Archive | AbBZip2.pas |
如果你需要动态判断格式并处理,可以用TAbArchive的类方法或者自己写一个工厂函数。下面是一个简单的格式判断逻辑:
function CreateArchiveForFile(const FileName: string): TAbArchive; var Ext: string; begin Ext := LowerCase(ExtractFileExt(FileName)); if Ext = '.zip' then Result := TAbZipper.Create(nil) else if Ext = '.tar' then Result := TAbTarArchive.Create(nil) else if Ext = '.gz' then Result := TAbGZipper.Create(nil) else raise Exception.CreateFmt('不支持的压缩格式: %s', [Ext]); Result.FileName := FileName; end;这段代码根据文件扩展名返回对应的压缩类实例。注意TAbZipper和TAbGZipper的接口略有差异,前者用AddFiles添加多个文件,后者通常只处理单个文件流。实际使用时需要根据具体格式调整调用方式。
3.3 压缩参数调优与内存管理
Abbrevia 提供了一些参数可以调整压缩行为。CompressionLevel前面提过,这里补充几个容易忽略的:
Zipper.StoreOptions:控制是否存储路径信息、是否覆盖已有文件等。常用值包括soStripPath(不存储路径)、soOverwriteFiles(覆盖同名文件)。Zipper.DeflationOption:选择压缩算法变体,一般用默认值就行。Zipper.TempDirectory:处理大文件时临时文件存放位置,默认是系统临时目录。
内存管理方面,Abbrevia 的类都继承自TObject,需要手动Free。如果在循环中频繁创建和销毁实例,建议复用同一个实例,只修改FileName属性。另外,TAbZipper在Save之后可以继续添加文件再Save,但每次Save都会重写整个压缩包,大批量操作时最好一次性添加完再保存。
注意:Abbrevia 3.05 的源码里有些地方用了
GetMem和FreeMem手动管理内存,如果你要修改源码,记得配对释放,否则容易出内存泄漏。
4. 避坑与排查:老版本 Delphi 集成时的五个血泪教训
Abbrevia 3.05 毕竟是有年头的库,在新旧环境里集成时会遇到各种玄学问题。下面这五条是我和同事实际踩过的,每条按「现象 → 原因 → 解决」写清楚,希望能帮你省点时间。
4.1 组件面板不显示 Abbrevia 标签页
现象:设计时包安装成功,但组件面板上找不到 Abbrevia 标签,重启 IDE 也没用。
原因:设计时包虽然编译通过,但没有正确注册组件。常见情况是.bpk文件里的Contains段没有包含所有需要注册的单元,或者 IDE 的组件缓存出了问题。
解决:打开B305cd61.bpk,检查Contains段是否列出了AbZIP.pas、AbGZIP.pas等单元。如果没有,手动添加后重新编译安装。如果还是不行,删除 IDE 的组件缓存目录(通常在用户目录下的.borland或Embarcadero文件夹里),重启 IDE 让它重建缓存。
4.2 编译时报「找不到 AbBase.dcu」
现象:新建项目引用 Abbrevia 单元后编译,提示File not found: 'AbBase.dcu'。
原因:Library Path 没有包含source目录,或者source目录下的.dcu文件版本不匹配。
解决:在 IDE 的 Library Path 里添加source目录的完整路径。如果之前编译过其他版本的 Abbrevia,先把source目录下所有.dcu文件删掉,重新编译包。注意.dcu文件是 Delphi 编译单元的输出,不同 Delphi 版本生成的.dcu不兼容。
4.3 解压含中文文件名的 ZIP 出现乱码
现象:用TAbUnZipper解压从其他系统传来的 ZIP 文件,中文文件名变成乱码。
原因:ZIP 格式对文件名编码没有统一标准,Windows 下常用 GBK,而 Abbrevia 默认按 ASCII 处理。如果压缩包是在 Linux 或 macOS 下创建的,文件名可能是 UTF-8 编码,直接解压就会乱码。
解决:Abbrevia 3.05 没有内置编码转换功能,需要在解压前手动设置文件名编码。一种做法是继承TAbUnZipper并重写GetFileName方法,在里面做编码转换。另一种更简单的做法是先用其他工具把 ZIP 里的文件名转成 ASCII,再交给 Abbrevia 处理。如果项目必须支持中文文件名,建议升级到更新版本的 Abbrevia 或换用其他库。
4.4 大文件压缩时内存暴涨
现象:压缩几百 MB 的文件时,进程内存占用飙升到几个 GB,甚至直接崩溃。
原因:Abbrevia 默认会把整个文件读入内存再压缩,处理大文件时内存消耗与文件大小成正比。
解决:设置Zipper.TempDirectory指向一个有足够磁盘空间的目录,Abbrevia 会在压缩过程中把中间数据写到临时文件。另外,可以分块读取文件,用TAbZipper.AddStream方法逐块添加,而不是一次性AddFiles。如果文件特别大,考虑用TAbZipper的流式接口,边读边压。
4.5 C++Builder 中链接报错「Unresolved external」
现象:在 C++Builder 6 里使用 Abbrevia,编译通过但链接时报Unresolved external 'AbZIP::...'之类的错误。
原因:C++Builder 需要.obj或.lib文件,而 Abbrevia 的包文件默认只生成了 Delphi 的.dcu。另外,C++ 名称修饰规则和 Delphi 不同,直接引用 Pascal 单元需要正确的extern声明。
解决:确认使用的是B305vr61.bpk和B305cr61.bpk这两个 C++Builder 专用包。编译时确保生成了.obj文件。如果还是报错,检查项目选项里的「Linker」设置,确保勾选了「Generate C++ object files」。必要时手动在 C++ 代码里用extern "C"包裹 Pascal 单元的引用。
5. 从示例到生产:把 Abbrevia 塞进真实项目的三个技巧
示例程序跑通只是第一步,真正集成到项目里还有不少细节要处理。这一章分享三个我在实际项目中用过的技巧,涉及批量压缩、进度反馈和格式兼容性验证。
5.1 批量压缩时的进度反馈与取消机制
Abbrevia 的TAbZipper提供了一些事件可以在压缩过程中触发,比如OnProgress和OnProcessItem。利用这些事件可以实现进度条和取消按钮。
type TForm1 = class(TForm) AbZipper1: TAbZipper; ProgressBar1: TProgressBar; btnCancel: TButton; procedure AbZipper1Progress(Sender: TObject; Progress: Integer); procedure AbZipper1ProcessItem(Sender: TObject; Item: TAbArchiveItem; var Abort: Boolean); end; procedure TForm1.AbZipper1Progress(Sender: TObject; Progress: Integer); begin // Progress 是 0-100 的整数,直接更新进度条 ProgressBar1.Position := Progress; Application.ProcessMessages; end; procedure TForm1.AbZipper1ProcessItem(Sender: TObject; Item: TAbArchiveItem; var Abort: Boolean); begin // 检查用户是否点击了取消按钮 if FCancelRequested then Abort := True; end;OnProgress事件的Progress参数是当前压缩进度百分比,直接赋给进度条即可。OnProcessItem在每处理一个文件时触发,把Abort设为 True 可以中止压缩。注意在事件处理里调用Application.ProcessMessages让界面保持响应,但别滥用,否则会拖慢压缩速度。
5.2 格式兼容性验证:用示例程序做回归测试
Abbrevia 支持多种格式,但不同格式之间的兼容性需要验证。我的做法是拿examples里的示例程序当回归测试工具:先用add.asp生成一个 ZIP,再用viewzip.asp查看内容,最后用extract.asp解压到另一个目录,对比源文件和解压后的文件是否一致。
这个流程可以脚本化。写一个批处理文件,依次调用编译好的示例程序,检查输出目录的文件数量和大小。如果某个格式的压缩包在解压后文件大小不一致,说明该格式的实现可能有问题,需要进一步排查。
对于 TAR 和 GZIP 格式,示例程序可能没有直接覆盖,需要自己写测试代码。我一般会构造一个包含各种类型文件(文本、二进制、空文件、大文件)的测试目录,分别用不同格式压缩再解压,对比 MD5 值。这个方法虽然笨,但能发现不少边界问题。
5.3 源码定制:修改压缩算法参数与扩展格式支持
Abbrevia 的源码可读性不错,如果你需要调整压缩算法参数或者添加新格式支持,直接改源码比等官方更新快。比如AbZIP.pas里定义了 ZIP 压缩的默认参数,你可以修改DeflationLevel的默认值来改变压缩行为。
扩展格式支持稍微复杂一些,需要继承TAbArchive并实现AddFile、ExtractFile等抽象方法。建议先通读AbBase.pas里的基类定义,理解接口约定后再动手。如果只是想支持一种新格式,可以先在examples里建一个测试项目,验证通过后再合并到主源码树。
提示:修改源码后记得更新
.bpk文件里的单元列表,否则重新编译包时不会包含新单元。
从那以后我每次拿到老库,都强制先跑一遍示例程序再动生产代码,这个习惯帮我省掉了至少三次通宵排查。希望帮到你。
本文还有配套的精品资源,点击获取