简介:XLSReadWriteII v6.0.0.47 是一款面向 Delphi 开发者的 Excel 文件读写组件,支持 D7 至 D10.3 Rio 等版本,适合需要在程序中直接操作 xls/xlsx 而无需安装 Excel 或其它办公软件的项目场景。组件自带针对单元格值优化的内存管理器,可处理较大文件,并提供 Direct Read 与 Direct Write 模式,在内存不足时直接对磁盘文件进行流式处理;其 XLSX 引擎依据文件格式规范自动生成,力求最大兼容性且不损坏、不篡改原有数据,同时不收取运行时费用并附完整源码。资源包为 rar 格式,共 596 个文件,约 2.59MB,包含 248 个 pas 源码单元、53 个 dfm 窗体、32 个 dpr 工程、16 个 dproj 项目文件,以及 html 文档、obj 编译单元、png/gif 图示与 cfg 示例配置等,覆盖源码、示例与说明文档。目前已有 299 人学习下载,适合希望深入掌握 Delphi 下 Excel 读写、参考示例工程与源码实现的中高级开发者。
1. 老 Delphi 项目里读写 Excel,为什么我最后留了这套 v6.0.0.47
接手一个维护了七八年的 Delphi 老系统时,最头疼的不是业务逻辑,而是导出报表。客户要 Excel,还得是带格式、带公式、能直接打印的那种。一开始用 OLE 自动化调 Excel 进程,服务器上没装 Office 直接崩;换成 CSV,客户嫌没有表头样式、数字变科学计数法。折腾几轮之后,我把目光放回了 XLSReadWriteII 这个老牌组件库,最终在项目里锁定了 v6.0.0.47 这个版本,同时兼容 D7 和 D10.3 Rio 两套编译环境。
这套东西解决的核心问题很明确:不依赖本机安装 Excel,直接在 Delphi 代码里生成和解析 xls/xlsx 文件,单元格样式、公式、多工作表都能控制。适合谁?还在维护 Delphi 老项目、需要程序化产出 Excel 报表、又不想被 Office 环境绑架的从业者。下面把我拆包、编译、踩坑的全过程摊开讲,新手能照着跑,熟手能直接看参数边界。
2. 拆包看结构:D7 与 D10.3 Rio 两套源码怎么摆
拿到压缩包先别急着装,先看清楚目录结构,这决定了你后面是走「编译源码」还是「装设计期包」。XLSReadWriteII 这类组件库通常分运行期包和设计期包,D7 和 D10.3 Rio 的包文件格式不一样,混用必翻车。
2.1 目录里到底有什么
解压后一般能看到这么几类东西,我按实际拆包经验列一下:
| 目录/文件 | 作用 | 对应版本 |
|---|---|---|
| Source 目录 | 核心单元源码,如 XLSReadWriteII2.pas 等 | 通用 |
| Packages 目录 | .dpk 包工程,分 D7 与高版本 | 按编译器区分 |
| Demo 目录 | 示例工程,含读写、样式、公式 | 通用 |
| Help/文档 | 接口说明与属性列表 | 通用 |
| Lib 目录 | 预编译的 .dcu | 按版本分 |
关键点在于:D7 用的是老式 .dpk 加 .dof 配置,D10.3 Rio 用的是 .dpk 加 .dproj,两者不能互相打开。我一般先确认自己主力的 IDE 是哪个,再决定编哪套包,不要想着一个包通吃。
2.2 先编运行期包,再编设计期包
顺序错了会报「找不到单元」或者「组件面板不出现」。正确流程是这样:
# 以 D10.3 Rio 为例,先打开运行期包工程 # 1. 用 IDE 打开 Packages 下对应版本的运行期 .dpk # 2. Build(不是 Compile),确保生成 .bpl # 3. 再打开设计期 .dpk,Install # 4. 检查组件面板是否出现 XLSReadWriteII 页签逻辑说明:运行期包(Runtime Package)提供实际功能代码,设计期包(Design Package)只负责把组件注册到 IDE 面板,它依赖运行期包。先 Build 运行期包是为了让设计期包能找到它引用的单元。参数上注意 Output 路径别指向系统目录,我习惯统一输出到项目下的 bin 目录,避免权限问题。
提示:D7 下没有 .dproj,改的是 .dof 里的搜索路径,把 Source 目录加进 Library Path,否则编译时报找不到 XLSReadWriteII2。
2.3 把 Source 路径加进搜索路径
不管哪个版本,Source 目录都要进搜索路径。D10.3 Rio 在 Tools → Options → Language → Delphi → Library 里加,D7 在 Project → Options → Directories/Conditionals 里加。加完之后新建一个空工程,uses 里写 XLSReadWriteII2,能编译过就说明环境通了。这一步是后面所有操作的地基,别跳过。
3. 写第一个导出:单元格、样式、公式三件套
环境通了之后,先跑一个最小可用的导出,把「新建工作簿 → 写单元格 → 设样式 → 存盘」这条链路走通。很多人一上来就搞复杂报表,结果卡在某个属性上不知道哪步错了。
3.1 最小导出代码
uses XLSReadWriteII2; // 核心单元,不同版本单元名可能略有差异 procedure TForm1.ExportDemo; var XLS: TXLSReadWriteII2; begin XLS := TXLSReadWriteII2.Create(nil); try XLS.Sheets.Add; // 新增一个工作表 XLS.Sheets[0].Name := '报表'; // 工作表命名 // 写表头 XLS.Sheets[0].AsString[0, 0] := '姓名'; XLS.Sheets[0].AsString[0, 1] := '金额'; // 写数据行 XLS.Sheets[0].AsString[1, 0] := 'A同学'; XLS.Sheets[0].AsFloat[1, 1] := 1234.56; // 写公式:对金额列求和 XLS.Sheets[0].AsString[2, 1] := '=SUM(B2:B2)'; XLS.Filename := 'D:\out\demo.xls'; XLS.Write; // 落盘 finally XLS.Free; end; end;逻辑说明:AsString、AsFloat 是按行列索引写值,索引从 0 开始,这点和 Excel 的 A1 表示法不一样,容易搞混。公式直接以字符串形式写入,前面带等号,组件会把它当公式处理而不是文本。Write 负责把内存中的工作簿写到 Filename 指定的路径。
参数说明:Sheets.Add 增加工作表,Sheets[0] 取第一个;AsFloat 写入的是浮点,避免金额被当文本;Filename 建议用绝对路径,相对路径在服务端跑的时候工作目录不确定,容易写到意想不到的地方。
3.2 样式设置别用错对象
样式是新手最容易翻车的地方。字体、边框、背景色分别挂在不同的对象上:
// 设置第一行表头加粗、居中、灰底 with XLS.Sheets[0] do begin CellFormat[0, 0].Font.Style := [fsBold]; CellFormat[0, 0].Alignment.Horz := ahlCenter; CellFormat[0, 0].Brush.BackgroundColor := clGray; CellFormat[0, 1].Font.Style := [fsBold]; end;逻辑说明:CellFormat 是按单元格取格式对象,Font 管字体,Alignment 管对齐,Brush 管填充。注意这些是「格式」不是「值」,写值和写格式是两条独立的线,互不覆盖。
参数说明:fsBold 是字体样式集合,可以叠加 fsItalic;ahlCenter 是水平对齐枚举,垂直对齐是 Alignment.Vert。颜色用 Delphi 的 TColor,别直接填 RGB 整数。
3.3 多工作表与命名冲突
一个工作簿里加多个 Sheet 时,名字不能重复,否则写盘时可能报错或者后一个覆盖前一个。我一般加完就立刻设 Name,并在代码里维护一个已用名字的集合做校验。另外 Sheet 数量多了之后,注意内存占用,几万行级别建议分批写或者用流式接口,别一次性全塞内存。
4. 读旧文件与兼容性:xls 和 xlsx 的边界在哪
导出跑通只是第一步,实际项目里更多是「读客户给的老 Excel,改完再存回去」。这一步的坑比写新文件多得多。
4.1 打开文件与读取单元格
procedure TForm1.ReadDemo(const AFile: string); var XLS: TXLSReadWriteII2; Row: Integer; begin XLS := TXLSReadWriteII2.Create(nil); try XLS.Filename := AFile; XLS.Read; // 读入文件 for Row := 0 to XLS.Sheets[0].LastRow do begin Memo1.Lines.Add( XLS.Sheets[0].AsString[Row, 0] + ' | ' + FloatToStr(XLS.Sheets[0].AsFloat[Row, 1])); end; finally XLS.Free; end; end;逻辑说明:Read 把文件加载进内存,之后就能按行列访问。LastRow 返回最后一个有数据的行号,用它做循环上界比写死行数安全。AsFloat 读数值单元格,如果单元格里其实是文本,读出来会是 0,这点要特别注意。
参数说明:AFile 传绝对路径;LastRow 是动态的,空表时可能是 0 或 -1,循环前最好判断一下。
4.2 xls 与 xlsx 的差异
v6 这个版本对两种格式的支持程度不一样。xls 是老二进制格式,读写都稳;xlsx 是压缩包结构,某些复杂样式或者图表读进来会丢。我实测下来,纯数据加基础样式的 xlsx 没问题,带数据透视表或者条件格式的,读进来大概率残缺。所以如果你的场景是「读客户模板」,先确认模板格式,xlsx 复杂模板建议让客户另存为 xls 再处理。
4.3 编码与中文乱码
中文乱码通常出在两个地方:一是文件本身编码,二是字符串转换。Delphi 老版本默认 AnsiString,D10.3 Rio 默认 UnicodeString,跨版本传字符串时如果不注意,中文就成问号。我的做法是统一在读写前后做一次显式转换,别依赖隐式转换。另外工作表名、单元格内容都建议用 UTF-8 思维去检查一遍。
注意:D7 下编译的代码拿到 D10.3 Rio 下重编,字符串类型变化可能导致原本正常的中文变乱码,迁移时这块要单独测。
5. 避坑与排查:那些让我加班到半夜的问题
这一章全是血泪经验,每条都按「现象 → 原因 → 解决」写,遇到对应症状直接对号入座。
5.1 编译报找不到单元
现象:uses 里写了核心单元,编译报「Unit not found」。 原因:Source 目录没进搜索路径,或者进的是错的版本目录。 解决:确认 Library Path 指向当前 IDE 对应的 Source,D7 和 D10.3 Rio 的路径分开配,别共用一份配置。
5.2 组件面板不出现
现象:设计期包 Install 了,但面板上找不到。 原因:设计期包没 Build 成功,或者运行期包没先 Build。 解决:先 Build 运行期包生成 .bpl,再 Build 并 Install 设计期包,顺序不能反。装完重启 IDE 再看。
5.3 写盘报文件被占用
现象:Write 时抛异常,提示文件无法访问。 原因:目标文件正被 Excel 打开,或者上一次的流没释放。 解决:写之前判断文件是否存在且被占用,必要时先改名备份;确保每次 Create 都有对应 Free,用 try...finally 包住。
5.4 公式不计算
现象:写进去的公式在 Excel 里打开显示为文本,不计算。 原因:公式字符串格式不对,或者单元格格式被设成了文本。 解决:公式必须以等号开头,且写入前别把该单元格格式设成文本格式。函数名用英文,参数分隔符用逗号。
5.5 大数据量导出卡死
现象:几万行导出时界面卡住甚至内存溢出。 原因:一次性全写内存再落盘,内存扛不住。 解决:分批写,或者用组件的流式接口;导出放后台线程,主线程只更新进度。别在主线程里干重活。
6. 进阶技巧:用模板 + 批量填充把报表做稳
前面都是单文件操作,实际项目里更常见的是「固定模板 + 动态数据」。我的习惯是先用 Excel 做好一个带样式的空模板,代码只负责往指定单元格填数,这样样式维护交给设计,代码只管数据,分工清楚,改版也方便。
具体做法:把模板文件放资源目录,运行时先 Read 模板,再按坐标写值,最后另存为新文件。坐标建议用常量或者配置表管理,别散落在代码里。下面是一个批量填充的骨架:
procedure TForm1.FillFromTemplate(const Tmpl, OutFile: string; const Data: array of array of Variant); var XLS: TXLSReadWriteII2; R, C: Integer; begin XLS := TXLSReadWriteII2.Create(nil); try XLS.Filename := Tmpl; XLS.Read; // 读模板,保留原有样式 for R := 0 to High(Data) do for C := 0 to High(Data[R]) do XLS.Sheets[0].AsString[R + 1, C] := VarToStr(Data[R][C]); XLS.Filename := OutFile; XLS.Write; // 另存,不动模板 finally XLS.Free; end; end;逻辑说明:先 Read 模板把样式带进来,再只覆盖数据区域,最后 Write 到新路径,模板文件本身不被修改。Data 用二维 Variant 数组传,兼容字符串和数字。
参数说明:R + 1 是假设第一行是表头,数据从第二行开始,这个偏移量按你模板实际结构调整;VarToStr 做统一转换,避免类型不匹配。
验证方法:导出后别只看代码跑没跑通,一定用 Excel 打开检查三件事——样式有没有丢、公式算没算、中文有没有乱码。我一般还会用另一个工具(比如开源的表格查看器)交叉验证一遍文件结构,确认不是只有 Excel 能打开。
从那以后我每次换 IDE 版本或者迁移项目,都强制先把这套组件的编译和最小导出跑一遍再动业务代码,省得后面分不清是环境问题还是逻辑问题。希望帮到你。
本文还有配套的精品资源,点击获取