踩坑爬坑系列……本来一个挺简单的问题,由于解决的方法太多,网上的博客太多,海量教程中想找到适合自己的方法实在太难了。下面是我看过的一些比较优秀的教程,整理记录一下:

从上面可以看到,我找了一大堆教程,实际上合适的只有最后一个——xlnt。下面就介绍一下,如何用xlnt这个开源库,非常非常简单的实现excel的读写。

对于大忙(懒)人,可以用我上传的资源(xlnt_demo,利用C++开源库xlnt读写excel,vs2015工程 ,免积分,觉得有用就关注一下博主),是编译好的vs2015工程,项目的属性设置都用的相对目录,无需改动,直接打开即可。

xlnt 编译

先去xlnt的github地址下载代码,再用cmake生成vs2015的工程。
按下面左图把Configure的编译器和位数(本文都用x64)设置好。按下面右图把多余的勾都去掉。不需要编译TEST、SAMPLES,CMAKE_INSTALL_PREFIX也不用改,它默认是build目录下的installed,编译成功后,生成的东西就在build/installed 目录下。installed目录下东西,就是下一步配置 xlnt 需要用的。

cmake 完成后,用vs2015打开工程。找到 菜单->生成->批生成,给 ALL_BUILD 和 INSTALL 的 Release x64 打勾就行,然后点击生成。如下图:

可能遇到的问题: error c2001: 常量中有换行符。原因:编码问题导致的。
解决办法:找到出现错误的 xlnt\source\detail\number_format\number_formatter.cpp ,在171行和467行,都出现了中文的引号,把它换成英文引号即可。然后再重新批生成一遍。我也暂时不理解那个文件的作用,有知道的朋友可以在评论区分享给大家。

当然,在Ubuntu系统下也能安装xlnt:xlnt在Ubuntu 16.04 的安装教程

xlnt 配置

批生成成功后,把 xlnt\build\installed 目录下四个文件夹(bin、include、lib、share),全部复制到自己vs工程的项目目录下(.vcxproj文件所在的目录)。理论上只需要include、lib文件夹,但是怕其他文件夹也会被依赖,所以干脆全复制过去。

注意xlnt与vs工程的版本和位数要一样(我的都是Release x64),否则会出现无法链接库的问题。
还要注意,上一步操作中,静态库的选项没有打勾,所以生成的是动态库xlnt.dll(在bin目录下),以后的程序运行都要带在这个dll。

四个文件夹复制过去之后,设置项目的属性(设置的时候检查一下是不是Release x64,否则设置无效):

  • 附加包含目录:$(ProjectDir)\include,用预定义的宏指定相对路径。
  • 附加库目录:$(ProjectDir)\lib
  • 附加依赖项:xlnt.lib
  • 最后再把 xlnt.dll 复制到项目目录和生成的exe所在的目录

以下的几个例子,都来源于 xlnt 的 examples,我只做点改动和注释。

读 excel

简单地读

#include <iostream>
#include <xlnt/xlnt.hpp>

int main()
{
    xlnt::workbook wb;
	wb.load("test_read.xlsx");
	auto ws = wb.active_sheet();
	std::clog << "Processing spread sheet" << std::endl;
	// 会把当前占用的单元格全都打印出来,空单元格则为空格。
	for (auto row : ws.rows(false))
	{
		for (auto cell : row)
		{
			std::clog << cell.to_string() << "\t";
		}
		std::clog << std::endl;
	}
	std::clog << "Processing complete" << std::endl;

	getchar();
	return 0;
}

输入的表格和输出的结果如下图所示:

把数据读入vector

#include <iostream>
#include <xlnt/xlnt.hpp>
#include <vector>

int main()
{
    xlnt::workbook wb;
    wb.load("test_read.xlsx");
    
    auto ws = wb.active_sheet();
	std::clog << "Processing spread sheet" << std::endl;
	std::clog << "Creating a single vector which stores the whole spread sheet" << std::endl;
	std::vector< std::vector<std::string> > theWholeSpreadSheet;
	for (auto row : ws.rows(false))
	{
		std::vector<std::string> aSingleRow;
		for (auto cell : row)
		{
			aSingleRow.push_back(cell.to_string());
		}
		theWholeSpreadSheet.push_back(aSingleRow);
	}
	std::clog << "Processing complete" << std::endl << std::endl;
	std::clog << "Reading the vector and printing output to the screen" << std::endl;
	for (int rowInt = 0; rowInt < theWholeSpreadSheet.size(); rowInt++)
	{
		for (int colInt = 0; colInt < theWholeSpreadSheet.at(rowInt).size(); colInt++)
		{
			std::cout << theWholeSpreadSheet.at(rowInt).at(colInt) << "\t";
		}
		std::cout << std::endl;
	}
	getchar();
    return 0;
}

输入的表格和输出的结果如下图所示:

写 excel

简单地写

#include <iostream>
#include <xlnt/xlnt.hpp>

int main()
{
    xlnt::workbook wb;
	xlnt::worksheet ws = wb.active_sheet();
	//赋值为数值
	ws.cell("A1").value(0.5);
	//设置单位格格式,设为百分比形式
	ws.cell("A1").number_format(xlnt::number_format::percentage());
	//赋值为字符串
	ws.cell("B2").value("string data");
	//赋值为公式
	ws.cell("C3").formula("=RAND()");
	//合并单元格
	ws.merge_cells("C3:C4");
	//冻结窗格
	ws.freeze_panes("B2");
	//保存
	wb.save("test_save.xlsx");
	
	getchar();
    return 0;
}

输出结果如下图所示,完全符合预期。

用vector批量写

#include <iostream>
#include <xlnt/xlnt.hpp>
#include <vector>
#include <string>

int main()
{
    std::vector< std::vector<std::string> > wholeWorksheet;
	for (int outer = 0; outer < 10; outer++)
	{
		std::vector<std::string> singleRow;
		for (int inner = 0; inner < 10; inner++)
		{
			//给vector中的每个元素赋值
			std::string val = std::to_string(inner + 1);
			singleRow.push_back(val);
		}
		wholeWorksheet.push_back(singleRow);
	}
	//创建工作簿
	std::clog << "Creating workbook" << std::endl;
	xlnt::workbook wbOut;

	//创建工作表,并把vector中的元素写入表格
	xlnt::worksheet wsOut = wbOut.active_sheet();
	//给工作表设置名称
	wsOut.title("data");
	std::clog << "Looping through vector and writing to spread sheet" << std::endl;
	for (int fOut = 0; fOut < wholeWorksheet.size(); fOut++)
	{
		std::clog << "Row" << fOut << std::endl;
		for (int fIn = 0; fIn < wholeWorksheet.at(fOut).size(); fIn++)
		{
			// 给单元格赋值。特别注意:工作表中的单元格下标是从1开始,而vector中的元素下标是从0开始
			wsOut.cell(xlnt::cell_reference(fIn + 1, fOut + 1)).value(wholeWorksheet.at(fOut).at(fIn));
		}
	}
	std::clog << "Finished writing spread sheet" << std::endl;
	wbOut.save("test_save.xlsx");

	getchar();
	return 0;
}

输出结果如下图所示:

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐