权双
发布于 2026-05-31 / 155 阅读
1

OpenXLSX:高效的 C++ Excel 库

OpenXLSX 是一个 C++ 库,仅支持C++17及以上版本。用于读取、写入、创建和修改 Microsoft Excel文件(.xlsx 格式)。在实际项目里,当你需要在 C++ 中生成报表、导出数据、读取配置表格时,OpenXLSX是一个不错的选择。

1 环境配置

为了确保代码的跨平台兼容性与可移植性,本库采用 CMake 作为核心构建系统。以下是经过严格验证的演示环境配置。

📊 环境总览

🖥️ 平台🔧 硬件配置💿 操作系统⚙️ 编译器工具链
WindowsIntel Core i5‑13490FWindows 11 ProVisual Studio 2019 (MSVC v142)
LinuxRaspberry Pi 4BDebian GNU/Linux 13 (trixie)gcc/g++

📦 下载项目
项目地址:https://github.com/troldal/OpenXLSX
git拉取:

git clone https://github.com/troldal/OpenXLSX.git

⚙️ 编译生成库目录结构
本库采用 CMake 构建,编译完成后将生成标准的开发目录结构。包含头文件、库文件以及 CMake 配置包,可直接被其他项目 find_package引用。

└─OpenXLSX_0_5_0
    ├─include
    │  └─OpenXLSX
    │      │  OpenXLSX.hpp
    │      │
    │      └─headers
    │              IZipArchive.hpp
    │              OpenXLSX-Exports.hpp
    │              ...(此处省略多个.hpp文件)
    │
    └─lib
        │  OpenXLSX.lib
        │  OpenXLSXd.lib
        │
        ├─cmake
        │  └─OpenXLSX
        │          OpenXLSXConfig.cmake
        │          OpenXLSXConfigVersion.cmake
        │          OpenXLSXTargets-debug.cmake
        │          OpenXLSXTargets-release.cmake
        │          OpenXLSXTargets.cmake
        │
        ├─OpenXLSX
        │      miniz.lib
        │      minizd.lib
        │      nowide.lib
        │      nowided.lib
        │      pugixml.lib
        │      pugixmld.lib
        │
        └─pkgconfig
                miniz-OpenXLSX.pc
                OpenXLSX.pc
                pugixml-OpenXLSX.pc

目录说明

路径类型作用描述
include/头文件存放 API 头文件
lib/*.lib库文件编译生成的静态库,d后缀代表 Debug 版本,无后缀为 Release版本
lib/cmake/CMake 包供 find_package(OpenXLSX)使用的配置文件,自动处理依赖
lib/OpenXLSX/依赖库库内部打包的第三方依赖(miniz, pugixml, nowide)
lib/pkgconfig/Pkg-config适用于 Linux/Mac 的 .pc文件,用于编译链接参数管理

1.1 Windows编译安装

1️⃣ 构建
我们选择 C:/package/OpenXLSX_0_5_0 作为安装目录,并为 Debug 版本添加后缀 d,避免同名库覆盖。

cmake -S . -B build ^
    -DCMAKE_INSTALL_PREFIX="C:/package/OpenXLSX_0_5_0" ^
    -G "Visual Studio 16 2019" ^
    -A x64 ^
    -DCMAKE_DEBUG_POSTFIX="d"

说明:-DCMAKE_DEBUG_POSTFIX="d" 会在 Debug 库名字后加上 d,这是因为Windows平台下,Release 和 Debug 编译的库是无法通用的,编译的 Debug 库后面加上 d 用于区分。

关于 x86 平台的说明:如果需要为 32 位 (Win32) 程序构建库,只需在配置时将 -A 参数修改为 Win32 即可。

平台-A参数值
x64-A x64
x86-A Win32

2️⃣ 编译

# Debug 模式
cmake --build build --config Debug -j 8

# Release 模式
cmake --build build --config Release -j 8

3️⃣ 安装
将编译产物(头文件、库、CMake 配置文件)安装到 C:/package/OpenXLSX_0_5_0目录:

# 安装 Debug 版本
cmake --install build --config Debug

# 安装 Release 版本
cmake --install build --config Release

1.2 Linux编译安装

1️⃣ 构建
我们选择 ~/package/OpenXLSX_0_5_0 作为安装目录。

cmake -S . -B build \
    -DCMAKE_INSTALL_PREFIX="~/package/OpenXLSX_0_5_0" \
    -DCMAKE_BUILD_TYPE=Release

说明: Linux环境下,需要在配置阶段指定编译类型,Linux下编译的Release和Debug库是可以混用的,因此在构建库的时候,一般指定为Release即可。

2️⃣ 编译

cmake --build build -j 8

3️⃣ 安装
将编译产物(头文件、库、CMake 配置文件)安装到 ~/package/OpenXLSX_0_5_0目录:

cmake --install build

2 常用API

设计理念:Document -> Workbook -> Worksheet -> Cell,逐层访问。

所有操作必须遵循这一层级链条,不可跳级访问

📊 层级调用关系图

┌─────────────┐
│  XLDocument │  (File IO)
└──────┬──────┘
       │ .workbook()
┌──────▼──────┐
│ XLWorkbook  │  (Sheet Management)
└──────┬──────┘
       │ .worksheet()
┌──────▼──────┐
│ XLWorksheet │  (Grid Container)
└──────┬──────┘
       │ .cell()
┌──────▼──────┐
│   XLCell    │  (Data R/W)
└─────────────┘

2.1 文档操作(XLDocument)

职责:负责文件的生命周期(创建、加载、保存)。

序号方法说明异常
1void create(const std::string& fileName, bool forceOverwrite);新建空文档forceOverwrite 如果不为 true且 fileName 已存在,create 将抛出XLException异常
2void open(const std::string& fileName);打开现有文件
3void save();保存到原路径XLException:OpenXLSX 检查失败;ZipRuntimeError:压缩文件访问失败
4void close();关闭并释放资源
5bool isOpen();检查是否已打开
6XLWorkbook workbook() const;获取工作簿对象

注意:在文档操作前首先要创建XLDocument文档对象,一切文档操作都是在XLDocument文档对象的基础上进行。

XLDocument doc;

用法示例

// 新建
doc.create("test.xlsx"); 
// 打开
doc.open("test.xlsx");     
// 保存
doc.save();                
// 关闭
doc.close();               
// 判断文档是否已打开
doc.isOpen()	          

2.2 工作簿(XLWorkbook)

职责:负责 Sheet 的管理(增、删、查)。

序号方法说明异常
1XLWorksheet worksheet(const std::string& sheetName);获取指定名称的Sheet
2void addWorksheet(const std::string& sheetName);新增 Sheet
3void deleteSheet(const std::string& sheetName);删除 SheetXLException: 如果尝试删除工作簿中的最后一个工作表,将抛出异常

⚠️ 工作簿默认存在一个名字位"Sheet1"的工作表,工作簿必须至少包含一个工作表。

注意:在工作簿操作前首先要从XLDocument创建XLWorkbook工作簿对象,一切工作簿的操作都是在XLWorkbook工作簿对象的基础上进行。

auto wbk = doc.workbook();

用法示例

// 获取
auto wks = wbk.worksheet("Sheet1");     
// 新建
wbk.addWorksheet("New");     	
// 删除
wbk.deleteSheet("Old");			

2.3 工作表(XLWorksheet )

职责:管理单元格的二维容器及区域遍历,说白了是管理如何找到想要的单元格。

序号方法说明
1XLCellAssignable cell(uint32_t rowNumber, uint16_t columnNumber) const;访问单元格(坐标方式)
2XLCellAssignable cell(const std::string& ref) const;访问单元格(字符串地址)
3XLCellRange range() const;获取当前数据区域
4XLCellRange range(std::string const& rangeReference) const;获取指定矩形区域
5uint32_t rowCount() const noexcept;获取工作表中的行数
6uint16_t columnCount() const noexcept;获取工作表中的列数

注意:在工作表操作前首先要从XLWorkbook创建XLWorksheet 工作表对象,一切工作表的操作都是在XLWorksheet工作表对象的基础上进行。

auto wks = wbk.worksheet("Sheet1");

用法示例

// 坐标法
auto wkc = wks.cell(1, 1);	
// 字符串地址法
auto wkc = wks.cell("A1");				
auto wkrange = wks.range();				
auto wkrange = range("A1:C3");
uint32_t row_count = rowCount();
uint16_t column_count = columnCount();

优先用坐标,不用 "A1"这种表示方法

2.4 单元格(XLCell)

职责:数据的读写与类型解析。

序号方法说明
1XLCellValueProxy& value();访问单元格(坐标方式)
2XLValueType type() const;访问单元格(字符串地址)
3.get<T>();获取数据

注意:在单元格操作前首先要从XLWorksheet 创建XLCell单元格对象,一切单元格的操作都是在XLCell单元格对象的基础上进行。

auto wkc = wks.cell(1, 1);

1️⃣ 写数据

wkc.value() = xxx;

举例

类型示例
字符串wkc.value() = "Name";
整数wkc.value() = 18;
浮点wkc.value() = 3.14;
布尔wkc.value() = true;

2️⃣ 读数据

⚠️ 核心原则:先判类型,再取值。

获取数据类型

auto type = wkc.value().type();

✖下面的写法是错误的,OpenXLSX不支持这种写法。

auto val = wkc.value();	

判断类型

类型枚举
OpenXLSX::XLValueType::Empty
字符串OpenXLSX::XLValueType::String
整数OpenXLSX::XLValueType::Integer
浮点OpenXLSX::XLValueType::Float
布尔OpenXLSX::XLValueType::Boolean
错误OpenXLSX::XLValueType::Error

源码定义如下

enum class XLValueType { Empty, Boolean, Integer, Float, Error, String };

根据数据类型获取数值

auto wkc = wks.cell(1, 1);
auto type = wkc.value().type();

if (type == OpenXLSX::XLValueType::String) {
    std::string s = wkc.value().get<std::string>();
}
else if (type == OpenXLSX::XLValueType::Integer) {
    int64_t i = wkc.value().get<int64_t>();
}
else if (type == OpenXLSX::XLValueType::Float) {
    double d = wkc.value().get<double>();
}
else if (type == OpenXLSX::XLValueType::Boolean) {
    bool b = wkc.value().get<bool>();
}
else if (type == OpenXLSX::XLValueType::Empty) {
    // 处理空cell ...
}
else{
    // 其它处理 ...
}

3️⃣ 结合工作表方法进行遍历

auto range = wks.range();
for (uint32_t r = 1; r <= range.numRows(); ++r) {
    for (uint32_t c = 1; c <= range.numColumns(); ++c) {
        auto wkc = wks.cell(r, c);
        // ... 数据的获取与处理
    }
}

3 OpenXLSX使用示例

📁 测试代码目录结构

└─OpenXLSX
    │  CMakeLists.txt
    │
    ├─file
    │      read_demo.xlsx
    │
    ├─read
    │      CMakeLists.txt
    │      read_demo.cpp
    │
    └─write
            CMakeLists.txt
            write_demo.cpp

🟦 编写顶层CMake配置文件
我们根据操作系统不同,将 OpenXLSX 的 CMake 配置路径设置不同路径,实际使用时请替换为你自己的安装位置。

  • Windows: C:/package/OpenXLSX_0_5_0/lib/cmake/OpenXLSX
  • Linux : ~/package/OpenXLSX_0_5_0/lib/cmake/OpenXLSX
cmake_minimum_required(VERSION 3.25)
project(TestOpenXLSX VERSION 1.0.0 LANGUAGES CXX)

if(NOT WIN32)
    set(LIBRARY_PATH  "~/package")
else()
    set(LIBRARY_PATH  "C:/package")
endif()

# Find dependency OpenXLSX
set(OpenXLSX_DIR "${LIBRARY_PATH}/OpenXLSX_0_5_0/lib/cmake/OpenXLSX")
find_package(OpenXLSX CONFIG REQUIRED)
if(OpenXLSX_FOUND)
    message( NOTICE "FOUND OpenXLSX" )
    get_target_property(OpenXLSX_INCLUDES OpenXLSX::OpenXLSX INTERFACE_INCLUDE_DIRECTORIES)
    message( NOTICE "OpenXLSX_INCLUDES is ${OpenXLSX_INCLUDES}" )
else()
    message( FATAL_ERROR "MISSING DEPENDENCY OpenXLSX" )
endif()

add_subdirectory(write)
add_subdirectory(read)

2.1 写Excel示例

✍️ 写Excel CMake配置文件

cmake_minimum_required(VERSION 3.25)
project(write_demo CXX)

add_executable(${PROJECT_NAME})

target_sources(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/write_demo.cpp )

# Configure linkage for ${PROJECT_NAME}
target_link_libraries(${PROJECT_NAME} PRIVATE OpenXLSX::OpenXLSX)
target_include_directories(${PROJECT_NAME} PRIVATE ${OpenXLSX_INCLUDES})
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17)

注意: OpenXLSX必须在C++17及以上才可使用。
✍️ 示例代码
下面这段代码演示了:创建一个 Excel 文档,增加删除sheet,写入不同类型的数据(浮点数、整数、字符串、布尔值),并以覆盖方式保存。代码注释标注出了与常用API的对应关系。
OpenXLSX有两种索引方式:

  • cell("A1"):代表A列第1个单元格
  • sheet.cell(1, 2):代表第1行第2个单元格
#include "OpenXLSX.hpp"
#include <string>
#include <vector>
#include <iostream>


void WriteExcel(const std::string& filename) {
    // Create an Excel document
    OpenXLSX::XLDocument doc;
    // XLDocument 1 : void create(const std::string & fileName, bool forceOverwrite);
    doc.create(filename, OpenXLSX::XLForceOverwrite);
    // XLDocument 5 : bool isOpen();
    if (!doc.isOpen()) return;
    // XLDocument 6 : XLWorkbook workbook() const;
    auto wbk = doc.workbook();

    // XLWorkbook 2 : void addWorksheet(const std::string& sheetName);
    wbk.addWorksheet("website");
    // XLWorkbook 3 : void deleteSheet(const std::string& sheetName);
    wbk.deleteSheet("Sheet1");   
    // XLWorkbook 1 : XLWorksheet worksheet(const std::string& sheetName);
    auto wks = wbk.worksheet("website");

    // XLWorksheet 1 : XLCellAssignable cell(uint32_t rowNumber, uint16_t columnNumber) const;
    auto wkc = wks.cell(1, 1);
    // XLCell 1 : XLCellValueProxy& value();
    wkc.value() = "https://pgmpocket.com/";
    // chain
    wks.cell("A1").value() = "https://pgmpocket.com/";
    wks.cell(1, 2).value() = "quanshuang";
    wks.cell("C1").value() = 2026;
    wks.cell(1, 4).value() = 3.14;
    wks.cell(1, 5).value() = true;
    
    // XLDocument 3 : void save();
    doc.save();
    // XLDocument 4 : void close();
    doc.close();
}

int main() {
    WriteExcel("write_demo.xlsx");
    return 0;
}

2.2 读Excel示例

✍️ 读Excel CMake配置文件

cmake_minimum_required(VERSION 3.25)
project(read_demo CXX)

add_executable(${PROJECT_NAME})

target_sources(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/read_demo.cpp )

# Configure linkage for ${PROJECT_NAME}
target_link_libraries(${PROJECT_NAME} PRIVATE OpenXLSX::OpenXLSX)
target_include_directories(${PROJECT_NAME} PRIVATE ${OpenXLSX_INCLUDES})
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17)

注意:OpenXLSX必须在C++17及以上才可使用。
✍️ 示例代码
下面这段代码演示了:读取一个 Excel 文档,由 main 函数接收一个传入参数,该参数为 Excel 文档路径。
与写 Excel 相同,OpenXLSX有两种索引方式:

  • cell("A1"):代表A列第1个单元格
  • sheet.cell(1, 2):代表第1行第2个单元格
#include "OpenXLSX.hpp"
#include <iostream>
#include <string>

struct Website {
    std::string url;
    std::string author;
    int year;
    int month;
};

void DirectReadExcel(std::string& filename) {
    OpenXLSX::XLDocument doc;
    // XLDocument 2 : void open(const std::string& fileName);
    doc.open(filename);
    // XLDocument 5 : bool isOpen();
    if (!doc.isOpen()) return;
    // XLDocument 6 : XLWorkbook workbook() const;
    auto wbk = doc.workbook();
    // XLWorkbook 1 : XLWorksheet worksheet(const std::string& sheetName);
    auto wks = wbk.worksheet("website");

    Website website{};
    // XLWorksheet 1 : XLCellAssignable cell(uint32_t rowNumber, uint16_t columnNumber) const;
    auto wkc = wks.cell("A2");
    // XLWorksheet 1 : XLCellValueProxy& value();
    // XLWorksheet 3 : .get\<T\>();
    website.url    = wkc.value().get<std::string>();
    website.author = wks.cell(2, 2).value().get<std::string>();
    website.year   = wks.cell("C2").value().get<int>();
    // XLWorksheet 2 : XLValueType type() const;
    if (wks.cell(2, 4).value().type() == OpenXLSX::XLValueType::Integer) {
        website.month = wks.cell(2, 4).value().get<int>();
    }
    
    // XLDocument 4 : void close();
    doc.close();

    std::cout << "DirectReadExcel : " << std::endl;
    std::cout << "url   : " << website.url << '\n'
        << "author: " << website.author << '\n'
        << "year  : " << website.year << '\n'
        << "month : " << website.month << std::endl;
    std::cout << std::endl;
}

void RangeReadExcel(std::string& filename) {
    OpenXLSX::XLDocument doc;
    // XLDocument 2 : void open(const std::string& fileName);
    doc.open(filename);
    // XLDocument 5 : bool isOpen();
    if (!doc.isOpen()) return;
    // XLDocument 6 : XLWorkbook workbook() const;
    auto wbk = doc.workbook();
    // XLWorkbook 1 : XLWorksheet worksheet(const std::string& sheetName);
    auto wks = wbk.worksheet("website");

    // XLWorksheet 3 : XLCellRange range() const;
    auto range = wks.range();
    std::cout << "RangeReadExcel : " << std::endl;
    for (uint32_t r = 1; r <= range.numRows(); ++r) {
        for (uint32_t c = 1; c <= range.numColumns(); ++c) {
            auto wkc = wks.cell(r, c);
            auto type = wkc.value().type();
            if (type == OpenXLSX::XLValueType::String) {
                std::cout << wkc.value().get<std::string>() << " ";
            }
            else if (type == OpenXLSX::XLValueType::Integer) {
                std::cout << wkc.value().get<int64_t>() << " ";
            }

        }
        std::cout << std::endl;
    }

    // XLDocument 4 : void close();
    doc.close();
}


int main(int argc, char *argv[]){
    if (argc != 2) {
        std::cerr << "Usage:" << argv[0] << " <filename>" << std::endl;
        return 1;
    }

    std::string filename = argv[1];  // Obtain the filename from command line arguments
    DirectReadExcel(filename);
    RangeReadExcel(filename);

    getchar();
    return 0;
}

2.3 编译运行

Windows和Linux在编译和运行上面稍有差异,因此本文会分别演示两种系统的操作流程。

2.3.1 Windows平台编译运行

首先进入项目目录:
1️⃣ 构建

cmake -S . -B build

2️⃣ 编译
可选择编译 Debug 版本或 Release版本

  • Debug模式
cmake --build build --config Debug
  • Release模式
cmake --build build --config Release

3️⃣ 运行

  • 运行写 Excel 程序
    找到write_demo.exe可执行文件,直接运行即可,运行结束后在程序目录下获得 write_demo.xlsx 文件,用 Excel 打开后将看到执行结果。
  • 运行读 Excel 程序
    找到read_demo.exe可执行文件,不可直接运行,需要传入 read_demo.xlsx 文件路径。
    ./read_demo.exe xxxxxxx/read_demo.xlsx
    

注意:其中xxxxxxx需要替换为 read_demo.xlsx 的实际路径。

运行结束后终端会打印运行结果。

2.3.2 Linux平台编译运行

首先进入项目目录:
1️⃣ 构建
Linux平台下是在构建时选择 Release 或 Debug

  • Release模式
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug=Release
  • Debug模式
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug

2️⃣ 编译

cmake --build build

3️⃣ 运行

  • 运行写 Excel 程序
    找到 write_demo 可执行文件,直接运行即可,运行结束后在程序目录下获得 write_demo.xlsx 文件,用 Excel 打开后将看到执行结果(可能系统未安装Excel软件,无法正常打开,为验证效果,可将 write_demo.xlsx 文件拷贝到Windows环境下查看运行效果)。
  • 运行读 Excel 程序
    找到 read_demo 可执行文件,不可直接运行,需要传入 read_demo.xlsx 文件路径。
    ./read_demo xxxxxxx/read_demo.xlsx
    

注意:其中xxxxxxx需要替换为 read_demo.xlsx 的实际路径。

运行结束后终端会打印运行结果。

3 总结

OpenXLSX 为 C++ 开发者提供了一种轻量、现代、跨平台的操作 Excel 文件的方式。
它彻底摆脱了对 Microsoft Excel 应用程序的依赖,仅通过一个头文件和少量静态库就能完成 .xlsx 的创建、读写与修改。配合 CMake 的 find_package 机制,它可以像标准库一样无缝集成到现有项目中,极大地降低了数据报表、记录导出等场景的开发成本。

如果你正在寻找一个 C++ 下简单可靠的 Excel 文件处理库,OpenXLSX 绝对值得一试。