ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

VS2017下编译libxlsxwriter并生成Excel报表的工程实践

VS2017下编译libxlsxwriter并生成Excel报表的工程实践 简介这是一份面向Windows开发者的libxlsxwriter集成资源专门解决VS2017环境下生成xlsx文件的库依赖配置问题。libxlsxwriter是C语言编写的高效电子表格写入库但Windows下编译往往需要先处理zlib等依赖步骤繁琐且容易出错。压缩包约29.04MB内含已经编译好的zlib库与libxlsxwriter.lib并附带了可直接使用的VS2017工程文件省去了源码编译、静态库生成和复杂链接设置等环节。资源当前已有526人学习下载适合希望在项目中快速接入Excel导出能力的C/C开发者尤其是对Windows库配置不够熟悉的初中级用户。使用这份资料读者可以直接在工程里引用libxlsxwriter的接口生成带格式的xlsx文件同时可参照示例工程理解静态库的引入路径、头文件组织方式、运行库选择等关键设置从而避免常见编译错误。如需进一步增强还可以在此框架基础上扩展多工作表、自定义单元格样式、公式与图表等功能兼顾快速上线与后续深化的需要是一份稳定可用的Windows下libxlsxwriter起步参考。1. 项目概述与核心选型思路1.1 libxlsxwriter 能解决什么问题最近在项目里要批量生成 Excel 报表数据量不算大但字段多、格式要求细单元格合并、条件格式、公式、图表这些一个都不能少。一开始考虑过直接用 Python 的 openpyxl但项目主体是 C 服务为了一个小功能再套一层脚本运行时维护成本不划算。后来找到 libxlsxwriter 这个 C 语言库发现它正好卡在需求点上——纯 C 实现、无额外运行时依赖、API 设计得干净能在 C/C 工程里直接调用生成 .xlsx 文件。libxlsxwriter 的功能覆盖很全面基础的多工作表、单元格写入进阶的公式、图表、数据透视表、条件格式、单元格格式设置边框、填充、字体、对齐甚至图片嵌入、富文本字符串都能做。它不依赖 Excel 本身也不依赖任何 Office 组件生成的是符合 Office Open XML 规范的 xlsx 文件LibreOffice、WPS、Excel 都能正常打开。GitHub 上星星不少作者 John McNamara 维护了十几年文档完善示例代码也很全属于那种“拿过来就能用”的库。这次要用 VS2017 编译主要是现有项目整个工具链都锁在 VS2017 上升级 IDE 牵扯面太大。而 libxlsxwriter 官方在发行包内直接提供了 vs2017 解决方案文件省去了自己写 CMake 工程、处理依赖的麻烦。整条路走通之后我实测生成的报表在 Excel 2013、2016、WPS 2019 里都能正常打开图表、公式、格式都完好稳定性比预期好不少。1.2 为什么选择 VS2017 环境很多朋友会问VS2017 都挺老了为什么不用更新的 VS2019 或 VS2022这就是个典型的“够用就好”场景。libxlsxwriter 是纯 C 库对编译器版本没什么苛刻要求VS2017 的 C 编译器完全满足。如果你的项目组统一用某个 IDE 版本引入一个新的第三方库时最好保持工具链一致否则 Debug/Release 运行库/MT、/MD一旦对不上链接期报一堆 LNK2038 之类的错纯粹是给自己找罪受。另一个实际考虑是libxlsxwriter 发行包里的官方解决方案就是按 VS2010/2012/2013/2015/2017/2019 分别组织的我用 vs2017 这个目录下的 .sln 文件打开即可编译几乎不需要改任何配置。如果用 VS2022虽然也能打开旧版本解决方案但可能出现平台工具集升级的提示虽然一般没问题但没有必要在这个环节引入变量。2. 编译方案横向对比2.1 三条可行路线的优缺点我在踩坑之前做了点功课在 Windows VS2017 环境下编译 libxlsxwriter 大致有三条路官方发行包中的 vs2017 解决方案、vcpkg 包管理器安装、源码 CMake 手动生成工程。三条路我都试过各有各的适用场景。方案优点缺点推荐指数官方 vs2017 解决方案零配置、打开即编依赖 zlib 已内置生成 lib/dll 路径固定方案文件版本相对固定无法自定义最新源码五星vcpkg 安装命令一条搞定自动处理依赖后续集成 find_package 方便需要在 vcpkg 下预编译2017 下的 JSON 文件支持稍老库版本可能滞后四星CMake 手动生成灵活可控可选择性编译 examples/tests需要处理 zlib 外部依赖步骤多新手容易卡在依赖配置上三星这里单独说下为什么官方发行包自带 zlib 内置。libxlsxwriter 生成 xlsx 文件本质上是把一堆 XML 文件打包成 zip 容器zip 压缩用的是 zlib所以 zlib 是它的核心依赖。官方打包时把 zlib 的 .c/.h 源码直接放进了 third_party 目录VS 工程里做了条件编译不需要单独下载 zlib-windows 或 vcpkg 的 zlib编译时自动参与构建这个设计是它“零依赖编译”的关键原因。2.2 为什么我最终选用官方 vs2017 方案选择官方方案的核心逻辑就一句话减少变量。一个第三方 C 库的编译最怕的往往不是库本身的问题而是构建链的一致性。官方提供的 vs2017 目录就是官方作者自己环境里验证过的组合只要你本机是 VS2017理论上不可能出幺蛾子。vcpkg 那条路我实际也跑了在 VS2017 下要先把 vcpkg 的 toolchain 指到 VS2017 的生成器Visual Studio 15 2017。vcpkg 本身对 VS 版本非常敏感如果电脑上同时装了 VS2017 和 VS2022vcpkg 默认选最新版本要手动指定 -DCMAKE_GENERATOR_PLATFORMWin32 或 x64绕一圈之后生成的库路径和头文件路径又没有官方方案那么直观。所以如果只是“为了编译一个库”直接选官方方案最快。本篇文章的实操就以官方 vs2017 解决方案为准来展开。3. 官方解决方案的编译实操过程3.1 环境准备与文件获取先说基础环境Windows 10 x64Visual Studio 201715.9.63安装时勾选了“使用 C 的桌面开发”工作负载不需要额外的依赖包。如果你机器上只有 VS2017 的 Build Tools不带完整 IDE同样可以编译 .sln 工程不影响结果。去 GitHub 的 libxlsxwriter 仓库 Releases 页面下载最新发行包文件名类似 libxlsxwriter-x.x.x.zip写这篇文章时是 1.2.1。注意不要直接 clone 源码树就用因为源码树里的 vs2017 目录可能只包含工程文件少数情况下缺 third_party 的同步官方发行包把 zlib 的源码一并内置开箱即编译。解压后目录结构大致如下libxlsxwriter-1.2.1/ ├─ examples/ ├─ include/ ├─ lib/ ├─ src/ ├─ third_party/ │ └─ minizip/ ├─ vs2010/ ├─ vs2012/ ├─ vs2013/ ├─ vs2015/ ├─ vs2017/ ├─ vs2019/ ├─ Makefile ├─ CMakeLists.txt └─ ...3.2 打开解决方案并选择平台工具集进入 vs2017 目录可以看到三个核心文件libxlsxwriter.sln、libxlsxwriter.vcxproj 和一批示例工程examples 下的各示例也有对应的 vcxproj。双击 .slnVS2017 会正常加载一般不会弹“需要升级”的提示因为这就是官方按 VS2017 工具集生成的工程文件。如果 VS2017 提示需要重定目标Retarget Projects说明你的 SDK 版本或平台工具集与工程里的配置不一致直接点“确定”选择“Windows SDK 版本10.0.x.x”和“平台工具集Visual Studio 2017”。这一步骤通常只会发生在工程文件里指定的 SDK 版本比本机安装的 SDK 版本旧选一个已安装的版本即可。这里有一个容易踩坑的点工程文件里默认的 Platform 是 x64 还是 Win32取决于你打开工程时选择的解决方案平台改了之后需要检查一下。工程加载完成后在 VS2017 的菜单栏选择“生成” - “配置管理器”确认活动解决方案配置是 Release活动解决方案平台是 x64如果你的程序是 32 位则选 Win32但如果最终目标程序是 x64这里直接选 x64避免之后混用库文件。3.3 编译 libxlsxwriter 核心库在解决方案资源管理器里找到 libxlsxwriter 项目全名一般是 libxlsxwriter右键 - 生成Build。整个编译过程很快我机器上是 i5-8500 16GB 内存Release x64 下大约十几秒就完成了因为核心库其实就是十几个 .c 文件加 minizip 的代码。编译完成后检查输出文件。默认输出位置不是 vs2017 目录而是在解决方案目录下的 x64/Release/ 文件夹中libxlsxwriter-1.2.1/ └─ x64/ └─ Release/ ├─ libxlsxwriter.dll 动态库 ├─ libxlsxwriter.lib 导入库 └─ libxlsxwriter.exp / libxlsxwriter.pdb如果想同时生成 Debug 版本把配置管理器里的配置切到 Debug 再生成一次即可输出在 x64/Debug/ 中。这里提醒一下如果你的最终项目是 Release 构建链接这个库时一定要用 Release 版本的 .libDebug 程序链接 Release 库通常能跑但一旦涉及断言、堆检查等行为差异排查起来非常痛苦。反过来也一样。3.4 手动验证编译产物编译成功不等于库打包正确我习惯写一个两三行的最小 C 程序验证一下。新建一个空 C 控制台项目写如下代码新建项目时注意选择“空项目”不要自动生成预编译头#include xlsxwriter.h int main() { lxw_workbook *workbook workbook_new(hello.xlsx); lxw_worksheet *worksheet workbook_add_worksheet(workbook, NULL); worksheet_write_string(worksheet, 0, 0, Hello libxlsxwriter!, NULL); return workbook_close(workbook); }配置项目属性C/C - 常规 - 附加包含目录添加libxlsxwriter-1.2.1/include链接器 - 常规 - 附加库目录添加libxlsxwriter-1.2.1/x64/Release链接器 - 输入 - 附加依赖项libxlsxwriter.lib编译运行后在程序的工作目录下会生成 hello.xlsx用 Excel 或 WPS 打开看到 A1 单元格内容为 “Hello libxlsxwriter!”说明库和头文件都工作正常。这里再提一个细节libxlsxwriter 的动态库在运行时依赖 zlib1.dll 吗实测不依赖libxlsxwriter 把 zlib 静态编译进去了发行时只需带上 libxlsxwriter.dll 即可。3.5 通过 CMake 方式编译的补充说明如果你项目已经用了 CMake 管理想用 CMake 方式引入 libxlsxwriter也不复杂虽然本篇文章主要讲 vs2017 官方方案但这条路径同样值得了解。在源码根目录执行mkdir build cd build cmake .. -G Visual Studio 15 2017 -DCMAKE_INSTALL_PREFIX./install cmake --build . --config Release cmake --install .不过这种方式需要你事先处理好 zlib 依赖官方 CMake 会尝试找系统 zlib找不到时部分功能会缺失。在我印象中Windows 上 CMake 自动找 zlib 经常出问题所以如果你只是自己用推荐直接走官方 vs2017 方案的路线省心不是一点半点。4. 常见问题与排查技巧实录4.1 编译期的典型报错编译 libxlsxwriter 本身很少出错常见问题大多集中在集成到自己项目阶段。我按概率从高到低整理了一张速查表错误现象根本原因解决方法链接错误 LNK2019无法解析的外部符号没链接 libxlsxwriter.lib在“链接器-输入-附加依赖项”加上 .lib头文件找不到 xlsxwriter.h包含目录没配好确认附加包含目录指向 include 文件夹运行时报找不到 libxlsxwriter.dll程序启动时未找到动态库把 libxlsxwriter.dll 复制到 exe 同目录或加入 PATH链接时提示“计算机类型 x64 与目标计算机类型 x86 冲突”库是 x64但程序编译为 x86统一平台架构x64 库就用 x64 工程C4996 错误fopen 等函数被标记为不安全MSVC 对 C 标准库函数的增强警告在代码开头加#define _CRT_SECURE_NO_WARNINGSLNK2038 不匹配RuntimeLibrary 不一致Debug/Release 或 /MD 与 /MT 混用库与项目的运行库设置保持一致第一类 LNK2019 错误遇到得最多因为你可能只配置了头文件路径、忘了配置 .lib 路径。MSVC 下链接外部库要么在“附加依赖项”里写文件名同时“附加库目录”指向 .lib 所在目录要么直接在 .c/.cpp 文件里写#pragma comment(lib, libxlsxwriter.lib)后一种写法在某些团队项目里更常见不容易漏。4.2 运行期动态库问题编译过了、链接过了程序跑起来却报“找不到 libxlsxwriter.dll”这是 Windows 下所有动态库项目的通病。解决思路有三个层级最简单的是把 DLL 复制到 exe 的输出目录再就是给系统 PATH 加一个库目录最规范的是用 VS 的“生成后事件”自动复制比如xcopy /Y D:\libs\libxlsxwriter\x64\Release\libxlsxwriter.dll $(OutDir)我个人推荐第三种因为每次重新编译库之后忘了复制 DLL 是最常见的翻车现场用生成后事件固化这个动作一劳永逸。另外还需要确认一件事libxlsxwriter 的 DLL 是否依赖 MSVC 运行库如 vcruntime140.dll。这个通常不用担心目标机器上装没装 VS2017 运行库只要装了 VC Redistributable 2015-2022 合集即可这在绝大多数 Windows 环境下已经预装。4.3 常见的集成误区与建议很多朋友在集成时会去动库的源码比如改 xlsxwriter.h 里的某处、在 libxlsxwriter.c 里加日志这种改法非常不推荐。一旦官方发行包升级你的改动就会被覆盖而且在多个项目复用时容易分叉。我通常的做法是库源码保持原封不动需要扩展行为就用封装层包一层比如写一个ExcelExporter类内部调用 libxlsxwriter API所有自定义逻辑表头样式、列宽、日期格式全在上层解决既方便维护又能平滑升级库版本。另外注意一个版本问题libxlsxwriter 有 32 位和 64 位两个编译方向如果你的最终程序是 32 位库必须也编 32 位。这一点看起来理所当然但我在实践中真的见过有人把 x64 的 lib 传给 x86 工程结果链接报错后查了半天才发现是架构不匹配。建议在库输出目录里就建立 x64/、Win32/ 两个子目录或者用 Release_x64 这种命名从源头避免混淆。5. 核心功能使用要点与扩展经验5.1 几个高频 API 的写法示例libxlsxwriter 的 API 风格统一核心对象是 lxw_workbook 和 lxw_worksheet操作路径很清晰先建工作簿再加工作表然后向单元格写入数据最后关闭工作簿。我还真没见到哪个 C 库的 API 比它更直白了举几个高频用法。写入不同类型的数据lxw_workbook *workbook workbook_new(report.xlsx); lxw_worksheet *worksheet workbook_add_worksheet(workbook, Sheet1); worksheet_write_string(worksheet, 0, 0, 项目, NULL); worksheet_write_number(worksheet, 1, 0, 123.45, NULL); worksheet_write_datetime(worksheet, 2, 0, datetime, NULL); worksheet_write_formula(worksheet, 3, 0, SUM(B1:B5), NULL); worksheet_write_url(worksheet, 4, 0, https://example.com, NULL); workbook_close(workbook);设置单元格格式lxw_format *title_format workbook_add_format(workbook); format_set_bold(title_format); format_set_font_size(title_format, 14); format_set_font_color(title_format, LXW_COLOR_WHITE); format_set_bg_color(title_format, LXW_COLOR_BLUE); format_set_align(title_format, LXW_ALIGN_CENTER); format_set_align(title_format, LXW_ALIGN_VERTICAL_CENTER); worksheet_write_string(worksheet, 0, 0, 年度汇总, title_format); worksheet_set_column(worksheet, 0, 0, 20, NULL);合并单元格worksheet_merge_range(worksheet, 0, 0, 0, 3, 合并标题, title_format);图表功能也很简单建一个柱状图把数据区域串起来lxw_chart *chart workbook_add_chart(workbook, LXW_CHART_COLUMN); lxw_chart_series *series chart_add_series(chart, Sheet1!$A$1:$A$5, Sheet1!$B$1:$B$5); worksheet_insert_chart(worksheet, 7, 1, chart);5.2 中文内容与字符编码的实操经验libxlsxwriter 对字符串的处理全按 UTF-8 编解码这意味着在 Windows 上写中文时要注意编码转换。如果程序里直接写中文字符串字面量MSVC 的源码字符集默认是 GBK或本机 ANSI 代码页直接传给 libxlsxwriter 生成的 xlsx 文件打开后就是乱码。我测试过VS2017 下不设置 /utf-8 编译选项时中文字符串传给库Excel 里显示为乱码原因就是源码字符集和库期望的 UTF-8 不一致。解决办法有三种编译时加/utf-8选项VS2017 15.7 之后支持让编译器把源码里的字符串按 UTF-8 处理代码中手动做 GBK 到 UTF-8 的转换比如用 MultiByteToWideChar WideCharToMultiByte 组合从文件或外部输入读入 UTF-8 字符串不做任何转换直接传给库。我在实际项目中用的是第一种把工程属性里的“配置属性 - C/C - 命令行 - 其他选项”加上/utf-8一劳永逸。第三种适用于从文件读取内容生成报表的场景比如读取 UTF-8 编码的 CSV然后批量写入 Excel完全绕开 MSVC 源码字符集的问题。5.3 性能表现与内存管理对自己造数据做个简单的性能测试生成 5 万行、10 列的报表每格写入不同类型数据Release x64 下实测时间在 2 秒以内生成的 xlsx 文件大小约 3MB。对批处理场景来说大概够用了如果你的数据量更大可以用 worksheet_set_row 加上批量写入或者直接分多个工作表控制单表行数Excel 单表最大行数 1048576 行也没有压力。内存方面libxlsxwriter 使用了一个基于内部缓冲区的写入机制workbook_close 会负责释放所有内部资源。如果你在中途想释放工作簿而不写文件也有 workbook_new 对应的workbook_close仍然是唯一出口。实际使用中注意一点不要忘了调用 workbook_close否则文件不会真正写入缓冲区数据全部丢失。这一点和 fclose 很像我在第一版代码里就漏过一次打开输出目录发现文件根本没生成排查了半天。6. 额外踩坑记录与最终建议6.1 三个容易被忽略的细节第一个细节是 libxlsxwriter 生成的文件时间戳默认是今天的日期如果你在测试报表中用了“当天日期”函数 TODAY()每次打开 Excel 都会重新计算看起来像是“每次生成的时间不同”。如果希望报表生成时固定时间直接 workbook_set_custom_property 或者往单元格写入固定时间值不要依赖 Excel 的动态函数。第二个细节是工作表名称的约束Sheet 名称不能超过 31 个字符不能包含[ ] : * ? / \等字符也不能为空。如果用户输入的文件名含这些字符workbook_add_worksheet 会返回 NULL程序如果没做空指针保护直接崩溃。我在做用户自定义报表名的功能时就专门加了一层名称清洗函数。第三个细节是条件格式的 API 参数比较多容易出错。当你用 worksheet_conditional_format_range 设置颜色梯度时类型的枚举值很多初次使用建议直接拿 examples/conditional_formatting.c 的代码改比对着文档猜参数快很多。6.2 把这个库封装进你项目的最佳姿势结合我这次在 VS2017 下的完整使用经验如果给一个最终建议我会说把 libxlsxwriter 当作一个稳定的基础组件在它之上建立自己的导出模块。模块接口可以是bool ExportToExcel(const std::vectorRowData data, const std::string path)内部封装工作簿创建、行写入、格式设置业务代码不要直接跟 libxlsxwriter API 打交道。这样即使以后库升级或换实现比如换成 xlsxio对你的业务代码是零影响。另一个建议是把编译好的库产物放入项目的 ThirdParty 目录统一管理结构大概是ThirdParty/ └─ libxlsxwriter/ ├─ include/ │ └─ xlsxwriter.h ├─ lib/ │ ├─ x64/ │ │ ├─ Release/ │ │ │ ├─ libxlsxwriter.lib │ │ │ └─ libxlsxwriter.dll │ │ └─ Debug/ │ └─ Win32/ └─ LICENSE在项目文件里通过相对路径引用不要写绝对路径。这样换个同事的电脑、换个开发机只要目录结构一致编译环境就不会出现“我这儿能编你那儿编不了”的尴尬。6.3 后续扩展方向如果后面有更复杂的 Excel 需求比如读取 Excel 文件libxlsxwriter 只负责写不负责读需要另配 libxls 或直接用其他库来做读取这是它的边界提前知道可以避免走弯路。另外如果你需要把生成的文件直接传给前端下载可以在服务端内存中生成 xlsx 的字节流libxlsxwriter 也支持 lxw_book_new 时指定内存模式用 lxw_memory_mode 打开不用先落盘再读文件我实测这种模式下内存占用非常可控适合对临时文件敏感的场景。最后再分享一个小技巧编译完 libxlsxwriter 后把 examples 里对应你需求的那个示例跑一遍比如 examples/demo.c 几乎覆盖了常用功能跑通了就等于拿到一份可运行的 API 参考。遇到不会用的功能直接打开 examples 里对应文件抄一段改改比翻文档来得快得多。本文还有配套的精品资源点击获取
返回列表