目的
因为有需求需要在PC上读取Excel文件,而且得要用C++来实现,故在Github上寻找了下好使的库,于是乎找到了Xlnt库
https://github.com/tfussell/xlnt
我采取了两个编译器VS2022和GCC10分别编译成库,然后调试
从Github上将源码将工程下下来,工程是CMAKE的
我的编译产物
VS2022编译库
直接打开CMakeSetting就可以配置CMAKE
很方便,不要选TEST,不需要测试相关的源码,当然也可以编成RELEASE的
注意,可能编译会提示有个别文件编码啥不对的,例如我这里是这个文件编码不对
解决的方法是文件,对编码异常的文件另存为
然后弹出的窗口,找到保存下的编码保存
选UTF-8带签名,替换保存
正常来说,编完之后,\out\build\x64-Debug\source 下得到Lib和DLL
头文件在\include下Xlnt文件夹下全部内容
VS2022编译DEMO
新建一个空白的工程
目录结构如下,lib下放编译好的lib文件,x64是输出的位置,把测试用的xlsx放进去
VC++目录界面
链接器设置界面
测试的代码
#include <iostream>
#include <xlnt/xlnt.hpp>
#include <Windows.h>
#include <wchar.h>
using namespace std;
std::string UTF8_To_string(const std::string& str)
{
int nwLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
wchar_t* pwBuf = new wchar_t[nwLen + 1];//一定要加1,不然会出现尾巴
memset(pwBuf, 0, nwLen * 2 + 2);
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), pwBuf, nwLen);
int nLen = WideCharToMultiByte(CP_ACP, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
char* pBuf = new char[nLen + 1];
memset(pBuf, 0, nLen + 1);
WideCharToMultiByte(CP_ACP, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);
std::string retStr = pBuf;
delete[]pBuf;
delete[]pwBuf;
pBuf = NULL;
pwBuf = NULL;
return retStr;
}
int main()
{
xlnt::workbook wb;
wb.load("test.xlsx");
auto ws = wb.active_sheet();
std::clog << "读取测试表格" << std::endl;
for (auto row : ws.rows(false))
{
for (auto cell : row)
{
//std::clog << cell.to_string() << std::endl;
string str1 = cell.to_string();
string str2 = UTF8_To_string(str1);
std::cout << str2 << "\t|";
}
std::cout << "\r\n";
}
std::clog << "读取完毕" << std::endl;
return 0;
}
测试的表格如下
运行的效果是这样的
注意,脱离调试环境运行的时候,需要把程序和DLL放在一起,如果在VS里调试可以不用。
GCC编译库
这里我用的是TDM-GCC,目前我下到的版本是gcc.exe (tdm64-1) 10.3.0
安装CMAKE,版本3.25.0-rc4
安装VSCODE,安装好CMAKE的插件,按照提示选好安装的GCC编译器,CMAKE应该就正常配置了
在下面可以配置CMake的输出类型和编译器
注意使用GCC编译Xlnt库,需要ninja,下载之后,把它可以放到安装GCC的bin目录下
关闭测试的代码,打开静态库
也是一样,万一有啥文件编码不正确的情况,请转换成UTF-8
输出的文件也是看\out\build\x64-Debug\source,得到.a文件
GCC编译DEMO
VSCODE新建一个工程文件夹,目录结构如下,lib放.a文件,src放源文件,include放相关头文件
.VSCode\c_cpp_properties.json文件
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/include/**",
"${workspaceFolder}/include/xlnt/**",
"${workspaceFolder}/include/xlnt/packaging/**",
"${workspaceFolder}/include/xlnt/styles/**",
"${workspaceFolder}/include/xlnt/cell/**",
"${workspaceFolder}/include/xlnt/drawing/**",
"${workspaceFolder}/include/xlnt/utils/**",
"${workspaceFolder}/include/xlnt/workbook/**",
"${workspaceFolder}/include/xlnt/worksheet/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "10.0.19041.0",
"compilerPath": "C:/TDM-GCC-64/bin/g++.exe",
"cStandard": "c11",
"cppStandard": "c++11",
"intelliSenseMode": "windows-gcc-x64",
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}
.VSCode\launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) 启动",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/main.exe",
"args": [],
"stopAtEntry": true,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "C:\\TDM-GCC-64\\bin\\gdb.exe",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "将反汇编风格设置为 Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
},
{
"name": "(gdb) Launch", // 配置名称,将会在启动配置的下拉菜单中显示
"type": "cppdbg", // 配置类型,这里只能为cppdbg
"request": "launch", // 请求配置类型,可以为launch(启动)或attach(附加)
"program": "${workspaceFolder}/${fileBasenameNoExtension}.exe",// 将要进行调试的程序的路径
"args": [], // 程序调试时传递给程序的命令行参数,一般设为空即可
"stopAtEntry": false, // 设为true时程序将暂停在程序入口处,一般设置为false
"cwd": "${workspaceFolder}", // 调试程序时的工作目录,一般为${workspaceFolder}即代码所在目录
"environment": [],
"externalConsole": true, // 调试时是否显示控制台窗口,一般设置为true显示控制台
"MIMode": "gdb",
"miDebuggerPath": "C:\\TDM-GCC-64\\bin\\gdb.exe", // miDebugger的路径,注意这里要与MinGw的路径对应
"preLaunchTask": "g++", // 调试会话开始前执行的任务,一般为编译程序,c++为g++, c为gcc
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
.VSCode\settings.json
{
"files.associations": {
"new": "cpp",
"atomic": "cpp",
"string_view": "cpp",
"iostream": "cpp",
"array": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"map": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"string": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"limits": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"typeinfo": "cpp"
}
}
源文件
#include <iostream>
#include <xlnt/xlnt.hpp>
#include <Windows.h>
#include <wchar.h>
using namespace std;
std::string UTF8_To_string(const std::string& str)
{
int nwLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
wchar_t* pwBuf = new wchar_t[nwLen + 1];//一定要加1,不然会出现尾巴
memset(pwBuf, 0, nwLen * 2 + 2);
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), pwBuf, nwLen);
int nLen = WideCharToMultiByte(CP_ACP, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
char* pBuf = new char[nLen + 1];
memset(pBuf, 0, nLen + 1);
WideCharToMultiByte(CP_ACP, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);
std::string retStr = pBuf;
delete[]pBuf;
delete[]pwBuf;
pBuf = NULL;
pwBuf = NULL;
return retStr;
}
int main()
{
xlnt::workbook wb;
wb.load("test.xlsx");
auto ws = wb.active_sheet();
std::clog <<"读取测试表格"<< std::endl;
for (auto row : ws.rows(false))
{
for (auto cell : row)
{
//std::clog << cell.to_string() << std::endl;
string str1 = cell.to_string();
string str2 = UTF8_To_string(str1);
std::cout << str2 << "\t|";
}
std::cout << "\r\n";
}
std::clog << "读取完毕" << std::endl;
return 0;
}
CMakeLists.txt
这个可能我写的复杂了,不过可以用
cmake_minimum_required (VERSION 2.8.12)#规定cmake的最低版本要求
project(Cmake_test)#项目的名称,不一定和你的文件夹名称一样
set(CMAKE_CXX_COMPILER "g++")#设置c++编译器
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fexec-charset=UTF-8")
set(SRC_MAIN ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp)
include_directories(${PROJECT_SOURCE_DIR}/include)
include_directories(${PROJECT_SOURCE_DIR}/include/xlnt)
include_directories(${PROJECT_SOURCE_DIR}/include/xlnt/packaging)
include_directories(${PROJECT_SOURCE_DIR}/include/xlnt/styles)
include_directories(${PROJECT_SOURCE_DIR}/include/xlnt/cell)
include_directories(${PROJECT_SOURCE_DIR}/include/xlnt/drawing)
include_directories(${PROJECT_SOURCE_DIR}/include/xlnt/utils)
include_directories(${PROJECT_SOURCE_DIR}/include/xlnt/workbook)
include_directories(${PROJECT_SOURCE_DIR}/include/xlnt/worksheet)
# 设置第三方库文件路径(这里全部的第三方库都保存在LIB_FILE变量中)
file(GLOB LIB_FILE ${PROJECT_SOURCE_DIR}/lib/*.a)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/build)#设置可执行文件输出路径
add_executable(main ${SRC_MAIN})
target_link_libraries(main ${LIB_FILE})
编译运行之后的效果