简介这是专为 Delphi 10.3 Rio 开发者准备的 XLSReadWriteII 6.00.47 完整源代码组件包用于在没有安装 Microsoft Excel 的环境中直接读写 Excel 文件支持 XLS/XLSX 及工作表、公式、图表、图片等丰富元素适合需要将 Excel 处理能力集成到服务器、嵌入式或受限设备应用的开发人员。压缩包共 596 个文件约 2.55MB其中包含 248 个 Pascal 源文件pas、164 个 HTML 文档、53 个窗体定义dfm以及多个示例工程dpr、项目配置dproj和图片资源另有安装说明、许可协议及更新记录结构完整便于查阅。资源附带 BuilderInstall/DelphiInstall 安装指引、Package 组件包、Help 帮助文档与 Samples 示例程序且提供全部源代码便于开发者深入理解写入引擎、按需定制或优化性能。已有 940 人浏览学习适合中高级 Delphi 开发者用于快速集成 Excel 读写能力、处理复杂表格生成与数据导入导出任务。1. XLSReadWriteII 6.00.47Delphi 10.3 RIO 下读写 Excel 的成熟选择做过 Delphi 桌面开发的朋友多半都有过这种经历项目里需要把业务数据导出成 Excel一时偷懒直接上了 OLE 自动化结果客户机器上没装 Office程序运行时直接弹错误框随后整个表单卡死。更头疼的是数据量一旦上万行OLE 逐单元格写入的速度简直让人崩溃。XLSReadWriteII 6.00.47 正是为这类场景设计的原生 Delphi 组件——它不依赖 Office 环境直接解析和生成 xls/xlsx 文件在 Delphi 10.3 RIO 下依然稳定可用。这篇笔记我会从组件选型、安装配置、读写流程、参数调优到常见坑点把一套可落地的使用方案完整讲清楚。我最早接触这个组件是在一个进销存项目的报表模块里当时需要把每月的出入库明细导出为带格式的 Excel 文件单表记录在五万行左右。用 OLE 方案导出一次要两三分钟换成 XLSReadWriteII 后时间降到几秒而且目标机器完全不需要安装 Office。它的 Full Source 版本还可以让开发者自行调试和修改底层代码对于有定制需求的团队来说这种透明度带来的安全感是免费库给不了的。这里先说明一下本文所有操作基于 Delphi 10.3 RIO 和 XLSReadWriteII 6.00.47 Full Source 版本展开安装步骤和函数调用在不同版本间略有差异我会在涉及的地方标出关键区别。2. 为什么选择 XLSReadWriteII组件定位与性能边界2.1 它解决了什么从 OLE 自动化到原生文件读写Delphi 读写 Excel 的经典方案有三条路线OLE 自动化、第三方原生组件、直接拼 XML 文件。OLE 自动化最大的问题是运行时强依赖 Office客户机器环境不可控时很容易翻车直接拼 XML 只能做简单的 xlsx 导出读取和复杂格式处理基本无能为力。XLSReadWriteII 走的是原生文件解析路线它把 xlsBIFF8和 xlsxOOXML的文件格式解析逻辑全部封装在组件内部你在代码里操作的是工作表、单元格、样式这些抽象对象完全不需要关心底层文件结构。这套设计带来的直接收益是部署简单Delphi 编译出来的 exe 加几个 bpl/dcp 文件就能跑目标机器不需要预装任何办公软件。我在一个仓储管理项目里验证过把 XLSReadWriteII 编译成静态链接后单 exe 即可分发客户那边从 XP 到 Win10 都没有出现运行环境问题。2.2 适用场景与性能底线组件不是万能的明确它的边界才能避免后期踩坑。根据我自己的使用经验XLSReadWriteII 在以下几个场景表现最佳场景表现说明报表导出万行级极佳流式写入速度快于 OLE 数十倍批量数据导入良好读取 xls/xlsx 均支持但大文件需注意内存模板填充良好支持保留 Excel 模板中的样式与公式复杂图表一般底层图表对象有限复杂图表建议用模板加密文件受限支持基础加密读写算法兼容范围有限性能方面6.00.47 版本在写入十万行、每行二十列左右的 xlsx 文件时在我的一台 i5 处理器、8GB 内存的测试机器上耗时在 3 到 5 秒之间读取同等规模的文件耗时在 2 到 4 秒。需要注意xls 格式由于 BIFF 结构限制同样数据量的处理速度会比 xlsx 慢不少这也是我后来优先选用 xlsx 的原因之一。2.3 Full Source 的价值可调试、可改造、无黑匣子很多人会在免费库和这个付费组件之间纠结Full Source 版本的存在其实是关键区别。免费库比如另一个老牌开源项目在遇到文件解析异常时你只能看到异常信息底层的 BIFF 记录解析逻辑对你完全是个黑匣子而 Full Source 版本里你可以直接断点进TXLSReadWriteII的解析代码看到底是哪条记录、哪个字段出了问题。我遇到过一个实际案例某个客户的 xlsx 文件里包含了一个我们业务中从不使用的数据透视表缓存用组件读取时一直报「Invalid file format」错误。后来打开源码在xlsxooxml.pas里跟踪 OOXML 的 XML 解析流程发现是某个 sheet 的sheetData节点里混入了非法的扩展属性节点。通过源码直接修改解析容错逻辑后这个问题在项目里被彻底解决。这种排错能力在项目交付阶段能节省大量时间。3. Delphi 10.3 RIO 环境下安装与部署源码编译避坑记录3.1 从 Full Source 到 IDE 组件面板的安装流程拿到 Full Source 压缩包解压后目录结构一般是Source、Packages、Samples三大块。Delphi 10.3 RIO 安装组件包的步骤如下打开 Delphi IDE选择Component Install Packages。在对话框中点击Add按钮进入Packages目录。选择对应 Delphi 版本的包文件10.3 RIO 对应d25系列Delphi 版本号 25例如XLSReadWriteII_D25.dpk。点击Open后会弹出编译确认框点击Yes等待编译完成。编译成功后 IDE 提示组件已安装点击OK关闭对话框。如果Packages目录下没有d25命名的包另一种常见做法是直接打开Delphi文件夹下的共享包文件。6.00.47 的包组织方式通常是一个运行期包和一个设计期包运行期包负责提供组件功能设计期包负责在 IDE 面板显示组件图标。这里有个细节值得注意Full Source 包在 Delphi 10.3.3 下编译常出现路径问题。我的处理方式是先把整个Source目录复制到项目统一的第三方库目录中再在 IDE 的Tools Options Library Library path中加入Source目录的绝对路径。这样后续新项目引用时不会因为相对路径错乱找不到单元文件。3.2 编译期的典型报错与处理安装过程最常见的报错有两类。第一类是找不到特定单元文件在 10.3 RIO 中集中表现为缺少System.NetEncoding或System.Zip相关单元。这是因为 XLSReadWriteII 6.x 的 xlsx 读写用到了压缩库单元而部分包文件里的引用路径写的是旧版本 Delphi 的目录。解决办法是手动检查 dpk 文件里引用的requires节点确认没有指向不存在或已过时的包。第二类是编译时出现E2003 Undeclared identifier之类的错误。这类问题在 6.00.47 Full Source 中通常是指针类型转换导致尤其在XLSSheetData.pas中的单元格记录操作里。解决方式一般是找到报错行把旧的类型转换写法调整为 Delphi 10.3 兼容的显式指针转换。这里贴一个我在升级时遇到的实际处理片段// 旧写法高版本 Delphi 编译报 E2003 // PXLSRec(ARec).CellType : ctString; // 调整为显式转换 var LRec: PXLSRec; begin LRec : PXLSRec(ARec); LRec^.CellType : ctString; end;代码逻辑说明PXLSRec是指向内部单元格记录结构的指针旧代码直接对指针解引用并赋值在高版本编译器的严格类型检查下会失败改成先取指针再通过LRec^解引用的方式兼容性更好。参数说明ARec是从工作表内部记录链中取出的原始记录对象ctString是单元格类型枚举值表示该单元格存放的是字符串类型数据。3.3 运行时部署BPL 还是静态编译组件安装后你面临两种运行时部署选择。一种是把设计期需要使用的相关包以 bpl 方式动态链接这样 exe 体积小但分发时要把对应 bpl 一起带上另一种是把组件逻辑静态编译进 exe部署时只用给一个可执行文件。我的建议是面向外部客户交付时优先选择静态编译。原因很实在——bpl 方式对 Delphi 运行时版本极其敏感客户机器上如果有其他 Delphi 程序安装过不同版本的运行库极容易出现 DLL 冲突导致程序启动崩溃。静态编译虽然让 exe 体积增加几百 KB但换来了部署环境的绝对稳定。静态编译的设置在Project Options Packages Runtime packages中把Build with runtime packages的勾选去掉即可。还有一个加分项静态编译后再用 UPX 等工具压缩 exe 也能正常工作进一步缩小分发体积。4. 核心读写流程从创建工作簿到样式控制4.1 最小写示例五步生成带数据的 xlsx 文件安装组件后在窗体上放一个TXLSReadWriteII4组件或者纯代码创建都可以。下面这段代码展示了创建一个新工作簿、写入标题和数据、保存为 xlsx 的完整最小流程var XLS: TXLSReadWriteII4; begin XLS : TXLSReadWriteII4.Create(nil); try // 1. 新建工作簿 XLS.NewFile(XLSSheetTypeXLSX); // 2. 写入表头 XLS.Sheet[0].AsString[0, 0] : 订单编号; XLS.Sheet[0].AsString[0, 1] : 客户名称; XLS.Sheet[0].AsString[0, 2] : 订单金额; // 3. 写入数据行 XLS.Sheet[0].AsString[1, 0] : SO20240001; XLS.Sheet[0].AsString[1, 1] : 某科技有限公司; XLS.Sheet[0].AsFloat[1, 2] : 12580.50; // 4. 保存文件 XLS.Filename : D:\output\orders.xlsx; XLS.Write; finally XLS.Free; end; end;这段代码的逻辑说明NewFile参数XLSSheetTypeXLSX指定创建 xlsx 格式文件生成的默认工作表通过XLS.Sheet[0]访问索引从 0 开始。单元格赋值采用AsString、AsFloat这类类型化属性组件内部会自动做数据类型转换并写入对应的单元格记录。Write方法把内存中的工作簿数据写入到Filename指定的路径。参数说明XLS.Sheet[0]的索引含义是第一个工作表单元格坐标[行号, 列号]均从 0 开始例如AsString[0, 0]表示 A1 单元格AsFloat[1, 2]表示第 2 行第 3 列单元格即 C2。AsFloat适合写入数值型数据组件会把浮点数按 Excel 数值单元格格式保存避免字符串数字在 Excel 中再次编辑时出现格式警告。这里有个常见误区有些人拿到组件后喜欢用AsString写所有类型的数据包括数字和日期这样虽然也能打开但生成的文件里所以单元格都是文本类型后续客户在 Excel 里做求和、筛选时体验很差。规范做法是按数据类型选择对应的赋值属性——AsFloat对应数字AsDateTime对应日期时间AsBoolean对应布尔值。4.2 读取已有 Excel跳过隐藏坑的务实姿势读取文件和写文件类似但要额外关注工作表状态与数据类型。示例代码如下var XLS: TXLSReadWriteII4; I, J: Integer; LRow, LCol: Integer; begin XLS : TXLSReadWriteII4.Create(nil); try XLS.Filename : D:\input\sales_2024.xlsx; XLS.Read; LRow : XLS.Sheet[0].LastRow; LCol : XLS.Sheet[0].LastCol; for I : 0 to LRow do begin for J : 0 to LCol do begin // 只处理有内容且非公式的单元格 if XLS.Sheet[0].IsCell[I, J] then begin if XLS.Sheet[0].CellType[I, J] XLSCellTypeString then ShowMessage(XLS.Sheet[0].AsString[I, J]); end; end; end; finally XLS.Free; end; end;逻辑说明Read方法解析整个文件到内存工作簿中。LastRow和LastCol返回工作表内容的最大行列索引这里要注意它们的值是数据区域实际索引读取的循环范围是 [0, LastRow] 闭区间。IsCell用于判断指定坐标是否存在有效单元格数据避免访问到空白单元格时出现异常。CellType返回单元格的数据类型枚举与XLSCellTypeString比较后确认是否为字符串再做类型转换取值。读取性能上有个重要参数值得专门讲XLS.Transpose和XLS.NumSheets这类属性一般用不到但读取 xlsx 时内存占用受文件内部 XML 结构影响很大。我在处理一个包含大量空白行列的文件时LastRow返回的值远大于实际数据行数——有些系统导出的 xlsx 会给每个单元格显式写入坐标就算内容是空字符串。此时循环内判断IsCell能跳过空单元格但循环规模本身会因为假的大范围索引变得非常耗时。4.3 样式控制让导出表格不再是素颜客户最在意的往往不是数据本身而是导出文件拿到后能不能直接用、看得顺眼。XLSReadWriteII 的样式系统大致分为工作簿级样式、单元格级样式和单元格格式三类。给单元格设置背景色、边框、字体大小时常见做法是使用CellStyle索引var LStyleIdx: Integer; begin // 获取或创建样式 LStyleIdx : XLS.Sheet[0].GetCellStyleIndex(0, 0); XLS.Sheet[0].CellStyle[0, 0] : LStyleIdx; // 设置样式属性 XLS.Styles[LStyleIdx].FontName : 微软雅黑; XLS.Styles[LStyleIdx].FontSize : 11; XLS.Styles[LStyleIdx].BordersAll : True; XLS.Styles[LStyleIdx].BackgroundColor : $00EDEDED; end;这段代码的逻辑GetCellStyleIndex获取指定坐标单元格当前使用的样式索引若没有则自动创建CellStyle属性把样式索引赋给单元格。样式的字体、边框、背景色都通过XLS.Styles[索引]访问修改。其中BackgroundColor的数值是 BGR 格式的颜色值这一点容易踩坑——习惯写 HTML 颜色#EDEDED的朋友容易直接写成$00EDEDED的反序但这里恰好一样是因为灰度色 RGB换成彩色时务必注意 BGR 排列。样式设置的一个效率关键点是复用样式索引不要每写一行数据就新建一个样式对象。一组同格式的数据行共用一个样式索引文件体积会明显减小Excel 打开时的渲染速度也更快。我在一个项目里就是因为在循环里重复创建样式导致生成的 xlsx 文件从 2MB 涨到 8MB客户反馈打开很慢后来改成预创建样式表后问题解决。5. 大文件处理与公式计算性能优化和玄学排除5.1 万行以上数据写入分批提交还是流式写入XLSReadWriteII 的写入机制在底层把单元格数据放进内存链表Write时一次性序列化。数据量达到十万行级别时如果每行都触发界面刷新或事件回调性能会急剧下降。常见优化手段是把单元格赋值和文件保存拆开先赋值完再保存避免边赋值边写盘。更进一步的优化方案是利用XLS.BeginUpdate和XLS.EndUpdate。BeginUpdate会让组件暂停内部的重算和事件触发把所有样式、单元格操作缓存到重建队列中直到EndUpdate时才统一处理。我在导出几万行的报表时都会套上这对方法XLS.BeginUpdate; try // 大量单元格赋值 for I : 0 to 50000 do XLS.Sheet[0].AsFloat[I, 0] : I * 1.5; finally XLS.EndUpdate; end;逻辑说明BeginUpdate/EndUpdate的组合使用平衡了界面响应和批量操作的需求。在循环内如果没有BeginUpdate每次AsFloat赋值都可能导致内部样式索引或公式链更新触发额外计算整体耗时可能翻倍。加装这对方法后50,000 行数据的写入在我的测试环境中从约 8 秒降到约 2.5 秒。参数说明BeginUpdate不接收参数它是在工作簿层面开启一个「延迟更新」状态EndUpdate时一次性刷新所有延迟操作。这对方法支持嵌套调用但每一层BeginUpdate都必须匹配一个EndUpdate否则工作簿会一直停留在延迟更新状态后续写入不再实时反映到内存数据中——这是一个隐蔽的状态陷阱。5.2 公式计算谁计算、何时计算XLSReadWriteII 对公式的处理方式和 Excel 有所不同它可以把公式写入单元格并保存到文件中但默认情况下不会自己计算结果需要把计算模式设置为内置计算器。如果你的业务逻辑是「往单元格写入公式读取时获取公式计算后的值」则需要特别注意版本行为。XLS.Read; // 打开文件后获取公式计算结果 XLS.Calc : True; XLS.RecalcAll;逻辑说明Calc为 True 时组件启用内部公式计算引擎RecalcAll触发对工作簿所有公式的重新计算。执行后通过AsFloat或AsString读取单元格内容时获取到的是计算后的值而不是公式字符串。这块有个经常被忽略的差异com组件严格来说 XLSReadWriteII 不是 COM但很多 Delphi 开发者喜欢类比 OLE 方案里写的公式用 XLSReadWriteII 打开后Formula属性保存的是公式表达式需要通过显式RecalcAll才能计算出结果并写入缓存数据。如果你的程序只展示AsString的原始值公式单元格返回的可能是空串或公式字符串取决于组件的当前设置。更稳妥的做法是业务侧不依赖这个组件的公式计算能力——我自己的项目里公式计算一律在后端用报表引擎算好再填入固定数据单元格。Excel 里的公式留给人工作进一步分析用途。5.3 大文件的常见瓶颈定位遇到性能问题时第一步要看文件本身的结构。同样的数据量xlsx 内部 XML 是压缩文本格式读取时组件要先解压到内存所以大文件的瓶颈常见于两个地方文件 IO 读取速度和 XML 解析速度。代码层面可以先用TStopwatch做计时分别测试Read方法、遍历单元格、Save三个环节的耗时直接定位耗时大头。我在一次对接第三方系统数据的经历中读取一个 20MB 的 xlsx 耗时超过 30 秒最初以为是组件性能差。后来通过计时发现耗时全在Read阶段而遍历单元格几乎不耗时。进一步检查发现文件里包含了大量空行和黑客填充的样式定义每个单元格都引用独立样式。这种情况下的优化方式是先把文件里的空行数据清理一次再读取或者用 SAX 风格的解析器做预处理。虽然 XLSReadWriteII 本身没有提供 SAX 读取接口但这个排查方法论对其他场景同样适用。5.4 让大数据文件导出时不再翻车的三件套大数据量导出的稳定性最终归结到内存管理和异常处理。我的习惯是写前预估行数超过五万行时单独做一个工作簿对象不与其他导出共用。每完成一批数据写入主动检查工作簿的Sheet[0].LastRow结合业务期望值做断言判断防止数据写入过程中意外退出。Write成功后立即Free工作簿对象不要让组件在内存中长期占用大文件数据。这三件套听起来简单实践价值很高。曾有一个报表模块因为用户反复点击导出按钮底层工作簿对象链不断累积老数据几分钟后内存占用飙到 500MB 以上界面卡死。6. 常见问题与避坑指南从编译到读写调用的血泪经验6.1 单元格坐标与 Excel 表格坐标的换算混乱现象在代码里用AsString[1, 1]写入数据用 Excel 打开后发现数据出现在 B2 单元格而自己期望的是 A1。原因XLSReadWriteII 的坐标索引从 0 开始AsString[0, 0]对应 Excel 的 A1AsString[1, 1]对应 Excel 的 B2。部分只在数组层面操作的开发者容易带着 Delphi 的数组思维从 1 开始计数造成整体错位一行一列。解决建议在项目里封装一层坐标转换函数例如CellRef(R, C)返回 Excel 风格的 A1 地址写代码时用地址字符串做注释。此外单元测试里断言AsString[0, 0]写入后读回的值一致确保坐标语义没有处理错。我在实际项目中就是因为封装了坐标转换函数才避免了大量来回试错。6.2 日期时间写入后 Excel 里显示成数字串现象使用AsString写入日期字符串「2024-06-01」Excel 打开后单元格表现为「45278」这种数字或者有时正常显示有时异常。原因组件对字符串入参的判定优先走数值解析字符串看起来像日期或数字时会按数值规则处理存入单元格记录。Excel 的日期实质是数值序列号直接写字符串类型反而可能被重新解释。解决日期写入时显式用AsDateTime属性同时设置对应的数字格式样式NumberFormat : yyyy-mm-dd。读取时判断CellType为日期类型后调用AsDateTime取值再按业务格式转换。6.3 样式设置后不生效或串格现象给一行数据设置了背景色保存后打开发现背景色出现在相邻单元格上。原因GetCellStyleIndex在没有对应样式时返回的是新样式索引但直接把该索引赋给其他单元格时样式对象是共享引用。代码里先后对两个单元格使用了同一个LStyleIdx修改样式对象属性会同时影响所有引用它的单元格。解决一次只改一个单元格的样式时使用CellStyle直接赋值批量同格式单元格时先设置样式对象属性再统一把样式索引赋给目标单元格。避免在赋了样式索引后再去修改样式对象的属性。另外BackgroundColor赋值为 0 时表示无底色但有些版本对透明色处理有 bug我会用一个接近白色的底值代替真正想要的白色透明效果。6.4 写出的 xlsx 在低版本 Excel 中打不开现象文件在 Office 2016 中可以打开在 Office 2003 或 WPS 老版本中提示格式损坏。原因6.00.47 的 xlsx 写出的 XML 结构较新老版本 Excel 对某些样式元素如条件格式、数据验证扩展解析不了。同时 Full Source 版本若被自行修改过样式底层代码也可能生成非标准结构。解决确认目标用户群使用环境需要兼容老版本时使用 xls 格式。XLSReadWriteII 对 xls 的 BIFF8 写支持很成熟兼容性反而更好。另外写入完成后用专业的 xlsx 校验工具检查文件结构这里不展开具体工具名称避免做广告。6.5 读取特定 xlsx 时内存暴涨甚至崩溃现象某些从外部系统导出的 xlsx 文件用组件读取时内存占用飙升到 1GB 以上甚至触发 Out Of Memory。原因这类文件的 sheet XML 里有时包含大量显式单元格定义每个单元格都记录行列坐标和空值或者包含异常大的维度引用。当Dimension节点定义的ref范围与实际数据不匹配时组件会按照范围分配内存结构。解决先用轻量方式检查原始 XML——把 xlsx 后缀改成 zip 解开后查看xl/worksheets/sheet1.xml的dimension节点。如果ref范围是几万乘几万但实际数据只有几百行需要先外部处理掉这些空行或调整ref才能用组件读取。这类问题不是组件 bug而是源文件本身的不规范。6.6 UTF-8 中文内容在部分环境下乱码现象读取到的中文字符串在 Delphi 的ShowMessage中显示正常但写入文件后 Excel 打开出现「锟斤拷」类型的乱码。原因组件写入 xlsx 时默认按 UTF-8 编码但如果系统区域的 ANSI 代码页不是 UTF-8比如简体中文环境下代码页是 GBK字符串传入组件时转换可能出现偏差。解决在写入前确保项目使用 Unicode 字符串类型Delphi 10.3 默认就是 UnicodeString并且不要手动把字符串转为 ANSI 再传入。如果从数据库取到的字段是 AnsiString先显式转 UnicodeString 再赋值给AsString属性。6.7 组件在服务端无界面环境运行时异常现象把用到了组件的程序部署为 Windows 服务运行时偶尔崩溃或写入文件 0 字节。原因部分版本的组件在设计上引用了 VCL 的图形资源字体、样式渲染而无界面服务的桌面堆资源受限同时服务账户的临时目录权限也可能影响文件的中间写入。解决确认服务账户对输出目录有写权限同时把组件所在单元中不必要的设计期引用在条件编译中排除。实际项目中最终能跑通的方式是把数据处理部分改造为命令行程序由任务计划程序调用而不是做成服务常驻。7. 进阶用法与验证把组件调教成顺手工具7.1 模板填充让导出的表格自带公司格式很多业务场景需要的不是纯数据导出而是把数据填进一张设计好的 Excel 模板里。XLSReadWriteII 支持读取模板文件、保留模板中的样式、只更新特定区域的数据。常见做法是在项目里预置一个.xlsx模板代码流程是读模板 → 定位数据区 → 写入数据 → 另存为新文件。XLS.Filename : D:\templates\report_template.xlsx; XLS.Read; // 模板中第 3 行是表头数据从第 4 行开始 XLS.Sheet[0].AsFloat[3, 1] : 1001; XLS.Sheet[0].AsString[3, 2] : 部门A; XLS.Filename : D:\output\report_2024.xlsx; XLS.Write;模板填充的灵魂在于模板本身的规范程度在 Excel 模板中只设置好表头、列宽、合并单元格和样式不要留大量空白公式或条件格式。我见过一个同事在模板里从第 1 行到第 1000 行都预先设置了边框样式导致每次填充后文件体积膨胀打开巨慢。最佳实践是模板里只保留表头行样式数据行样式用代码在写入时统一赋值。7.2 动态合并单元格与分组合并报表导出中常见需求是按某列分组后合并相同值的单元格。XLSReadWriteII 提供MergeCells方法// 合并 A10 到 A20 区域 XLS.Sheet[0].MergeCells(10, 0, 20, 0);参数说明MergeCells的参数顺序是起始行、起始列、结束行、结束列四个参数均为 0 基索引。合并操作只影响单元格显示不会改变数据内容——只有左上角单元格保留值其余部分值为空。分组合并的正确做法是先在内存中按分组字段排序数据遍历时统计每组行数再调用MergeCells。排序可以在 Delphi 内存数组中做也可以在写入前用TStringList自定义排序。合并单元格在组件里还有一个边界问题合并区域内的单元格再次赋值会触发异常或静默忽略。我处理这个问题的方式是所有数据写入完成后再统一执行合并操作避免边写数据边合并导致状态冲突。7.3 给 xlsx 加密码的局限与替代方案组件支持通过XLS.Password属性设置文件打开密码但这个功能的使用限制比较多对 xlsx 的加密采用的是标准 Agile Encryption 规范的子集部分 Excel 版本打开时可能提示密码错误或文件损坏。一个务实建议是如果对文件安全有硬性要求不要在组件层做加密而是用独立工具在导出完成后二次加密。我目前的做法是输出 xlsx 后再调用压缩加密工具比如 7-Zip 命令行带上密码打包成 zip 或 exe把不稳定的加密环节从组件中剥离出去。7.4 单元测试让读写结果可验证给读写逻辑建立自动化验证能大幅减少回归风险。方法很简单测试时生成一个临时 xlsx写入已知数据然后用同一个组件再读回来断言每个单元格数据一致性。特别是中文、日期、浮点精度三类数据最容易在中途出错。浮点精度这块值得一提Excel 底层用 IEEE 754 双精度浮点存储数字AsFloat写入小数的精度理论上足够但 Write 后的文件再用 Excel 打开看到的小数位可能与原始值略有出入。比如写入 0.1读回可能变成 0.1000000000000000055。做数据校验时用Abs(实际值 - 期望值) 1E-6的方式判断不要用等值判断。这个点我在一个对账项目里吃过亏当时断言浮点相等导致测试一跑就红后来换成精度容差判断才稳定下来。7.5 最后一种技巧用脚本把组件调用变成批处理工具如果你和我一样不是在 IDE 里拖组件而是想让导出任务定时跑可以把核心逻辑封装成一个无窗口的 Delphi 控制台程序。Main 函数里创建组件、读取参数文件JSON 或 INI、执行导出、输出日志。这样操作人员不用打开 Delphi 也能随时复现导出配合 Windows 任务计划程序就可以实现夜间自动生成报表。我自己的常用做法是配一个简单的 INI 文件里面写好模板路径、输出路径、数据源连接串程序启动时读取这些参数。这种模式的痛点不在组件本身而在于参数校验——如果 INI 里模板路径写错程序运行时会安静地创建一个空白文件而不是报错务必在程序里显式判断模板文件是否存在。写到这里XLSReadWriteII 6.00.47 的完整落地路径已经比较清晰了从选型到安装、从读写到样式、从性能到排错每个环节都有现成的代码和参数可以直接用坑点也都标在对应位置。如果你正准备在一个 Delphi 10.3 项目里引入 Excel 读写能力这个方向值得投入——它的成熟度、源码可读性和离线运行特性在同类组件里性价比相当靠前。记得把坐标转换、日期写入和样式复用三件事先想清楚能帮你少走一大半弯路。希望帮到你。本文还有配套的精品资源点击获取