IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 使用ODBC操作Excel文件 -> 正文阅读

[C++知识库]C++ 使用ODBC操作Excel文件

C++ 使用ODBC操作Excel文件

一、ODBC介绍

? 开放数据库连接(Open Database Connectivity,ODBC)是为解决异构数据库间的数据共享而产生的,现已成为WOSA(The Windows Open System Architecture(Windows开放系统体系结构))的主要部分和基于Windows环境的一种数据库访问接口标准。ODBC 为异构数据库访问提供统一接口,允许应用程序以SQL 为数据存取标准,存取不同DBMS管理的数据;使应用程序直接操纵DB中的数据,免除随DB的改变而改变。用ODBC 可以访问各类计算机上的DB文件,甚至访问如Excel 表和ASCI I数据文件这类非数据库对象。

二、环境

Visual Studio 2015

三、项目搭建

创建有MFC环境的32位控制台程序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5i0Nkm1f-1648544714884)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1648539324315.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lNxCHKza-1648544714885)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1648539641855.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EADr3dvW-1648544714886)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1648539680414.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PFMVHo4L-1648544714886)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1648539788824.png)]

提示: 32位控制台程序只是用于本地测试,程序代码还可以移植到其它有MFC环境的程序中。

四、编码

0)移除默认生成文件

将默认生成的代码文件移除,看着乱

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gAwxKvf7-1648544714887)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1648540104890.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kDJvL5hk-1648544714887)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1648540145116.png)]

1)excel_util.h

操作excel工具类的头文件

#include <iostream>
#include<stdlib.h>
#include <vector>
#include <map>
#include <afxdb.h>
#include <afx.h>
using namespace std;

CString get_columns_str(CString columns[], int columns_num);
CString get_create_sheet_sql(CString sheetName, CString columns[], CString columns_type[], int columns_num);
void WriteToExcel(CString filePath, CString sheetName, CString columns[], CString columns_type[], int columns_num, vector<vector<CString>> dataVec);
vector<vector<CString>> ReadFromExcel(CString filePath, CString sheetName, CString columns[], int columns_num);

2)excel_util.cpp

编写操作excel的工具类代码

#include "excel_util.h"

/*
获取sheet页的各列列名,返回格式如:[列1,列2,列3,···]
@param columns		sheet的各列名的数组
@param columns_num	sheet的列数
@author				lds
*/
CString get_columns_str(CString columns[], int columns_num)
{
	//printf("-----------------get_columns_str start ---------------\n");
	CString columns_str = "";  // 拼接的表头字符串,如:aa,bb,cc,dd
	for (size_t i = 0; i < columns_num; i++)
	{
		if (i == 0) {
			columns_str = columns_str + columns[i];
		}
		else
		{
			columns_str = columns_str + "," + columns[i];
		}
	}
	//printf("columns_str:[%s]", columns_str);
	//printf("-----------------get_columns_str end ---------------\n");
	return columns_str;
}

/*
获取创建excel的sheet页的sql语句
@param database		odbc数据源连接对象
@param sheetName	创建的sheet页名称
@param columns		sheet页的每列首行标题
@param columns_type	sheet页的每列单元格的类型
@param columns_num	sheet页的总列数
@return sql			创建excel的sheet页的sql语句
@author				lds
*/
CString get_create_sheet_sql(CString sheetName, CString columns[], CString columns_type[], int columns_num)
{
	//printf("----------------------get_create_sheet_sql start ------------------------\n");
	//创建表结构
	CString sql = "CREATE TABLE " + sheetName + "(";
	for (size_t i = 0; i < columns_num; i++)
	{
		if (i == 0) {
			sql = sql + columns[i] + " " + columns_type[i];
		}
		else
		{
			sql = sql + "," + columns[i] + " " + columns_type[i];
		}
	}
	sql = sql + ")";
	//printf("----------------------get_create_sheet_sql end ------------------------\n");
	return sql;

}

/*
使用ODBC往Excel里写数据。
@param filePath		创建excel文件的地址			如:C:/demo.xlsx;文件不存在时会自动生成
@param sheetName	创建的sheet页名称			如:sheet1
@param columns		sheet页的每列首行标题
如:CString columns[11] = { "序号","任务名称","物料识别码","对应的流程","设计人" ,"状态","当前任务信息","当前节点责任人","开始时间" ,"持续时间(天)","完成时间" };
@param columns_type	sheet页的每列单元格的类型
如:CString columns_type[11] = { "NUMBER","TEXT","TEXT","TEXT","TEXT" ,"TEXT","TEXT","TEXT","TEXT" ,"NUMBER","TEXT" };
@param columns_num	sheet页的总列数				如:int:11
@param data			待写入的所有数据
如:vector<vector<CString>> data = {
{ "1","名称1","识别码1" ,"流程1" ,"设计人1" ,"状态1" ,"任务信息1" ,"责任人1" ,"2022-03-10 16:38:07" ,"0" ,"2022-03-10 16:38:11" },
{ "2","名称2","识别码2" ,"流程2" ,"设计人2" ,"状态2" ,"任务信息2" ,"责任人2" ,"2022-03-10 16:38:07" ,"0" ,"2022-03-10 16:38:11" },
{ "3","名称3","识别码3" ,"流程3" ,"设计人3" ,"状态3" ,"任务信息3" ,"责任人3" ,"2022-03-10 16:38:07" ,"0" ,"2022-03-10 16:38:11" },
{ "4","名称4","识别码4" ,"流程4" ,"设计人4" ,"状态4" ,"任务信息4" ,"责任人4" ,"2022-03-10 16:38:07" ,"0" ,"2022-03-10 16:38:11" }
};
@author				lds
*/
void WriteToExcel(CString filePath, CString sheetName, CString columns[], CString columns_type[], int columns_num, vector<vector<CString>> dataVec)
{
	printf("-------------------------WriteToExcel start----------------------------\n");
	CDatabase database;
	CString sDriver = "Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)";//Excel安装驱动
	CString sql; //db执行语句
				 //创建进行存取的字符串
	sql.Format("DRIVER={%s};DSN='Excel nFiles';READONLY=FALSE;DBQ=%s", sDriver, filePath);;
	//创建数据库(即Excel表格文件)
	try
	{
		if (database.OpenEx(sql, CDatabase::noOdbcDialog))
		{
			CRecordset recset(&database);
			// 查询sheet页是否存在,不存在则创建
			sql = "select * from " + sheetName;
			// cout << "查询sheet页是否存在sql:[" << sql << "]" << endl;
			try
			{
				recset.Open(CRecordset::forwardOnly, sql, CRecordset::readOnly);
				// printf("----sheet页已经存在!\n");
			}
			catch (...)
			{
				// printf("----sheet页不存在!创建sheet页!\n");
				sql = get_create_sheet_sql(sheetName, columns, columns_type, columns_num);
				// cout << "create sheet sql:[" << sql << "]" << endl;
				try
				{
					database.ExecuteSQL(sql);
					// printf("create [%s] sheet success!\n", sheetName);
				}
				catch (...)
				{
					printf("create [%s] sheet is fail!\n", sheetName);
				}
			}

			printf("Startting To Write Data In Excel...\n");
			// 获取各列名
			CString columns_str = get_columns_str(columns, columns_num);
			// 循环插入数据
			int success_count = 0;  // 插入数据成功个数
			int error_count = 0;  // 插入数据成功个数
			for (int i = 0; i < dataVec.size(); i++)
			{
				sql = "insert into " + sheetName + "(" + columns_str + ")VALUES(";
				vector<CString> rowData = dataVec[i]; // 每行数据
				for (int j = 0; j < rowData.size(); j++)
				{
					if (j == 0)
					{
						sql = sql + "\'" + rowData[j] + "\'";
					}
					else
					{
						sql = sql + "," + "\'" + rowData[j] + "\'";
					}
				}
				sql = sql + ")";
				// cout << "insert sql:[" << sql << "]" << endl;
				// 逐行写入
				try {
					database.ExecuteSQL(sql);
					success_count = success_count + 1;
				}
				catch (...)
				{
					printf("insert data is fail!SQL is [%s]\n", sql);
					error_count = error_count + 1;
				}

			}
			printf("All Data Write To Excel complete!Success count:%d;Error count:%d。\n", success_count, error_count);
		}
	}
	catch (...) {
		printf("Register ODBC Driver Is Fail!\n");
	}
	//关闭数据库
	database.Close();
	printf("-------------------------WriteToExcel end----------------------------\n");
}

/*
使用ODBC读Excel表格数据
@param filePath		创建excel文件的地址			如:C:/demo.xlsx;文件不存在时会自动生成
@param sheetName	创建的sheet页名称			如:sheet1
@param columns		sheet页的每列首行标题
如:CString columns[11] = { "序号","任务名称","物料识别码","对应的流程","设计人" ,"状态","当前任务信息","当前节点责任人","开始时间" ,"持续时间(天)","完成时间" };
@param columns_num	sheet页的总列数				如:int:11
@return				sheet页所有行数据
@author				lds
*/
vector<vector<CString>> ReadFromExcel(CString filePath, CString sheetName, CString columns[], int columns_num)
{
	printf("-------------------------------ReadFromExcel start------------------------------\n");
	//获取查询结果
	vector<vector<CString>> rows;   // sheet页所有行数据(不包含首行-标题行)
	CDatabase database;
	CString sql;
	CString driver = "Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)";
	printf("driver:[%s]", driver);
	//创建进行存储的字符串
	CString ssql;
	ssql.Format("ODBC;DRIVER={%s};DSN='Excel nFiles';DBQ=%s", driver, filePath);
	//打开数据库
	try
	{
		if (database.Open(NULL, false, false, ssql))
		{
			/*
			要实现对结果集的数据操作,就要用到CRecordSet类。
			CRecordSet类定义了从数据库接收或者发送数据到数据库的成员变量,CRecordSet类定义的记录集可以是表的所有列,也可以是其中的一列,这是由SQL语句决定的。
			CRecordSet类的成员变量m_hstmt代表了定义该记录集的SQL语句句柄,m_nFields成员变量保存了记录集中字段的个数,m_nParams成员变量保存了记录集所使用的参数个数
			*/
			CRecordset recset(&database);
			//设置读取的查询语句
			CString columns_str = get_columns_str(columns, columns_num);
			sql = "SELECT " + columns_str + " FROM " + sheetName;
			printf("执行的查询sql是:[%s]\n", sql);
			//执行查询语句
			try
			{
				recset.Open(CRecordset::forwardOnly, sql, CRecordset::readOnly);
				while (!recset.IsEOF())
				{
					vector<CString> row;
					for (int i = 0; i < columns_num; i++)
					{
						CString item;
						recset.GetFieldValue(columns[i], item);
						printf("%s:%s;", columns[i], item);
						row.push_back(item);
					}
					printf("\n");
					rows.push_back(row);
					//移动到下一行
					recset.MoveNext();
				}
			}
			catch (...)
			{
				printf("执行查询sheet页数据失败!\n");
				printf("可能原因1:sql的列标题与实际的excel列标题对应不上!sql的列标题是: [%s],请检查excel的列标题!\n", columns_str);
				printf("可能原因2:执行查询sheet页数据的sql有问题,sql是: [%s]\n", sql);

			}
			database.Close();
			printf("Read Excel is complete!Results count is %d\n", rows.size());
		}
	}
	catch (...)
	{
		printf("Register ODBC Driver Is Fail!\n");
	}
	printf("-------------------------------ReadFromExcel end------------------------------\n");
	return rows;
}

3)main.cpp

程序入口,进行测试。

#include "excel_util.h"

int main()
{
	CString columns[11] = { "序号","任务名称","物料识别码","对应的流程","设计人" ,"状态","当前任务信息","当前节点责任人","开始时间" ,"持续时间(天)","完成时间" };
	CString columns_type[11] = { "NUMBER","TEXT","TEXT","TEXT","TEXT" ,"TEXT","TEXT","TEXT","TEXT" ,"NUMBER","TEXT" };
	vector<vector<CString>> data = {
		{ "1","名称1","识别码1" ,"流程1" ,"设计人1" ,"状态1" ,"任务信息1" ,"责任人1" ,"2022-03-10 16:38:07" ,"0" ,"2022-03-10 16:38:11" },
		{ "2","名称2","识别码2" ,"流程2" ,"设计人2" ,"状态2" ,"任务信息2" ,"责任人2" ,"2022-03-10 16:38:07" ,"0" ,"2022-03-10 16:38:11" },
		{ "3","名称3","识别码3" ,"流程3" ,"设计人3" ,"状态3" ,"任务信息3" ,"责任人3" ,"2022-03-10 16:38:07" ,"0" ,"2022-03-10 16:38:11" },
		{ "4","名称4","识别码4" ,"流程4" ,"设计人4" ,"状态4" ,"任务信息4" ,"责任人4" ,"2022-03-10 16:38:07" ,"0" ,"2022-03-10 16:38:11" }
	};
	// cout << size(columns) << endl;
	CString filePath = "E:/writeDemo1111.xlsx";
	CString sheetName = "mysheet1";
	int columns_num = size(columns);
	WriteToExcel(filePath, sheetName, columns, columns_type, columns_num, data);
	vector<vector<CString>> results = ReadFromExcel(filePath, sheetName, columns, columns_num);
	system("pause");
	return 0;
}

4、最终项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0eBv1UNh-1648544714889)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1648542163975.png)]

五、测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cIhoM0gc-1648544714890)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1648542964113.png)]

在这里插入图片描述

本地可以看到excel成功生成了,并且数据也是正确写入了

在这里插入图片描述
在这里插入图片描述

六、可能异常及解决

异常一:预编译头未使用

在这里插入图片描述

解决:

在这里插入图片描述

异常二:参数类型转换异常

在这里插入图片描述

解决:

在这里插入图片描述

异常三:未知编码格式错误

在这里插入图片描述

在这里插入图片描述

解决:

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dnldnbKp-1648544714894)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1648541283248.png)]

[外链图片转存中...(img-JLfhC1SN-1648544714892)]

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-30 18:05:26  更:2022-03-30 18:05:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:25:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码