用XLNT库读写Excel文件
经常会有生成Excel文件的需求,用C++生成Excel报表比较简单的方法是用MSOFFICE的OLE实现,这种兼容性最好,而且网上容易找到解决方案。但是这种方案要求电脑上装有MS Office软件,运行速度不高。
另一种方案就是直接读写EXCEL文件,感谢开源,我们可以找到不少读写EXCEL的库。XLNT是其中一个功能比较完整的C++开源库,基地在此:https://github.com/tfussell/xlnt
西加加斯基(www.cpp-prog.com) 原创,欢迎转载。
安装
再次感觉开源(和微软),我们可以用vcpkg这样方便的包管理工具,编译安装C++库和Linux下一样方便。直接输入下面的命令就可以装好xlnt了。
1 | vcpkg install xlnt |
等有空了专门写一下vcpkg,它的基地在此:https://github.com/microsoft/vcpkg, 后面的代码为了方便演示类型,使用了明确的名空间和类型名,实际写代码时推荐用
auto
会方便很多。
操作Workbook
记得包含头文件
1 |
首先从Workbook开始。
只需声明xlnt::workbook
就可以新建一个Workbook,一番猛如虎的操作后调用void save(const std::string &filename)
方法保存出Excel文件。
1 | xlnt::workbook wb; |
打开一个Excel文件同样简单
1 | xlnt::workbook wb; |
操作Worksheet
在XLNT里,我们可以把xlnt::workbook
看成是xlnt::worksheet
的容器:
1 | xlnt::workbook wb; |
而且xlnt::workbook
提供了很多与Worksheet相关的方法
create_sheet
、copy_sheet
方法来生成新表remove_sheet
方法删除表active_sheet
得到当前活动表sheet_by_title
,sheet_by_index
用于得到指定名字或序号的表,
操作Cell
Cell就是Excel里的单元格,XLNT中类型是xlnt::cell
,前面的例子已经出场过了。
定位
单元格可以通过”A1”, “C5”这样的EXCEL地址来定位, 如:
1 | ws.cell("A1").value(5); |
也可以用行列序号来定位,左上角是(1,1),如:
1 | ws.cell(2,1).value(5); // 第二列, 第一行(即B1)数值设置成5 |
XLNT库提供了xlnt::cell_reference
类来表示位置信息,用它可以方便的在行列与EXCEL地址之间转化。
1 | xlnt::cell_reference cr("C5"); |
遍历
1 | xlnt::worksheet ws = wb.active_sheet(); |
如果把一张表(Worksheet)看成是一个二维单元格数组的话,那么xlnt::cell_vector
就是一维单元格数组,这样看上面的聚合关系就明确了。
我们还可以用下面的方法得到现有数据在表中的最大使用范围:
1 | row_t worksheet::highest_row() |
数值读写
1 | bool cell::has_value() const; |
value
是一个模板方法,可以接受或返回多种数据类型。data_type
指明了当前数据类型。
公式读写
1 | bool cell::has_formula() const; |
公式以等号=
开头
注释读写
1 | bool cell::has_comment(); |
Range
一个矩形区域内的单元格可以组成一个xlnt::range
。
1 | xlnt::workbook wb; |
同样的, Range也是一个二维表格, 所以它也是xlnt::cell_vector
的容器。遍历方法与前面Worksheet的相同。
定位
Range的定位要左上角和右下角,除了刚才演示的EXCEL地址写法,也可以用两个xlnt::cell_reference
或四个数字指定。
与Cell一样,XLNT库也提供了xlnt::range_reference
类来表示位置信息,用它可以方便的在行列与EXCEL地址之间转化。
1 | xlnt::range rg = ws.range(xlnt::range_reference{2, 2, 5, 4}); |
1 | xlnt::range rg = ws.range(xlnt::range_reference{ |
另外,上面这个也可以简写成这样:
1 | xlnt::range rg = ws.range({ |
字体, 边框, 对齐, 填充
xlnt::cell
有一个format
方法,可以设置和取得格式。不过更简单的设置方法是这样的:
1 | xlnt::workbook wb; |
xlnt::range
也有对应的方法
其它
上面介绍的功能只是XLNT库的一小部分,还有更多功能不能涉及,官方文档也不丰富。这里必须再再次感谢开源,我们可以直接看代码知道内部实现,了解功能。
问题和坑
用第三方库来读写EXCEL有一个很讨厌的问题就是兼容性,虽然xlsx也算是一种公开的格式,但谁也不知道微软在EXCEL里做了什么特殊的小动作。
所以我不推荐用XLNT来读取EXCEL保存的文件,至少目前会遇到各种问题。请坚持只用XLNT读写自己写的文件。
下面是我在用的过程中遇到的一些问题,(XLNT 1.4.0)
- 删除行和删除列操作不会处理合并单元格,如“A1:A5”合并,这时删除第一行后会发现第一格并没有变成”A1:A4”,而且原来A6的数据不见了。
- 遍历时单元格用
formula
写的公式不会被has_value
或has_formula
探测到。 - XLNT打开Excel写的文件时抛异常。