C++使用ODBC读写Excel文件详细介绍

本文介绍了使用ODBC方式对Excel文件进行读写操作的步骤,包括查看已安装的ExcelODBC驱动、读取Excel文件数据、写入Excel文件。通过C++代码示例展示了如何创建连接字符串、读取字段信息以及写入数据。这种方法适用于需要高效读写但不涉及复杂功能的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

程序开发中,经常需要读取excel文件数据或将数据写入excel,当前主要的操作方式有COM和ODBC方式两种。COM方式功能强大,但读写效率较低。ODBC方式读写速度快,但功能相对较少,如无法获取excel文件内所有sheet的名称,无法写入公式等。
本文主要记录使用ODBC对excel进行操作中的主要步骤:

一、头文件

#include <afxdb.h>
#include <odbcinst.h>

二、查看系统中已安装的Excel ODBC驱动

1、系统中查看已安装ODBC数据源

可通过系统中odbc数据源查看当前已安装的odbc驱动,需要注意区分32位及64位ODBC驱动,要对应所开发的程序是32位应用还是64位应用。
搜索odbc数据源
在这里插入图片描述

2、程序获取ODBC中Excel驱动

程序获取ODBC Excel Driver可以通过读取读取注册表及ODBC API两种方式获得。

读取注册表方式

已安装的odbc driver均保存在注册表中HKEY_CURRENT_USER\Software\ODBC\ODBC.INI\ODBC Data Sources键下:
在这里插入图片描述

实现代码如下:

CString GetExcelOdbcDriver()
{
	HKEY hKey;
	long lResult;
	int i = 1;

	if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\ODBC\\ODBC.INI\\ODBC Data Sources"), 0, KEY_READ, &hKey))
	{
		TCHAR szKeyValue[256] = { 0 };
		DWORD cbValue = 256 * sizeof(TCHAR);

		if (ERROR_SUCCESS == RegQueryValueEx(hKey, _T("Excel Files"), NULL, NULL, (LPBYTE)szKeyValue, &cbValue))
		{
			CString Keydata(szKeyValue);
			return Keydata;
		}
		else
		{
			RegCloseKey(hKey);
			return _T("");
		}

	}
	return _T("");
}
ODBC API方式

需要用到ODBC API函数SQLGetInstalledDrivers,得到所有已安装ODBC Driver,实现如下:

CString GetExcelDriver()
{
	TCHAR szBuf[2001];
	WORD cbBufMax = 2000;
	WORD cbBufOut;
	TCHAR *pszBuf = NULL;
	CString sDriver;

	//获取已安装驱动的名称
	if (!SQLGetInstalledDrivers(szBuf, cbBufMax, &cbBufOut))
		return _T("");

	pszBuf = szBuf;
	//检索已安装的驱动是否有Excel...
	do
	{
		if (StrStr(pszBuf, _T("Excel")) != 0 && StrStr(pszBuf, _T("xlsx")) != 0)  //csv
		{
			//发现excel驱动
			sDriver = CString(pszBuf);
			break;
		}
		
		int i =  0;
		while (pszBuf - szBuf <= cbBufMax - i && pszBuf[i] != _T('\0'))
			i++;

		if (pszBuf - szBuf > cbBufMax - i)
			return _T("");

		pszBuf += i + 1;
	} while (pszBuf[0] != _T('\0'));

	return sDriver;
}

三、读取Excel文件数据

1、打开Excel文件

首先需要创建连接字符串,然后调用CDatabase::OpenEx方法。

CDatabase database;
CString sDsn;
CString sFilePath= _T("d:\\test.xlsx");
CString sDriver = GetExcelDriver();
//创建连接字符串
sDsn.Format(_T("DRIVER={%s};DSN='Excel nFiles';DBQ=%s"), sDriver, sFilePath/*excel文件路径*/);
// 打开数据库(Excel文件)
if (database.OpenEx(sDsn, CDatabase::noOdbcDialog))
{
	...
}
database.Close();

2、读取字段信息

将Sheet当做数据表进行读取,将第一行作为标题,也就是数据表字段。需要用到结构体CODBCFieldInfo,其定义如下:

struct CODBCFieldInfo
{
	// meta data from ODBC
	CString m_strName;
	SWORD m_nSQLType;
	SQLULEN m_nPrecision;
	SWORD m_nScale;
	SWORD m_nNullability;
};

读取字段信息代码如下:

CRecordset recset(&database);
CString sSql=_T("SELECT * FROM [Sheet1$]");

// 执行查询语句
if (recset.Open(CRecordset::forwardOnly, sSql, CRecordset::readOnly))
{	
	//获取字段总数
	int nColCount = recset.GetODBCFieldCount();
	
	CODBCFieldInfo fieldInfo;
	for (int k = 0; k < nColCount ; k++)
	{
		recset.GetODBCFieldInfo(k, fieldInfo);
		std::cout << k << ":" << fieldInfo.m_strName.Trim() << std::endl;
	}
}

3、读取表中数据

读取数据使用CRecordset::GetFieldValue,该函数重载四种参数组合,可以以CString及CDBVariant类型输入数据。

void GetFieldValue(LPCTSTR lpszName, CDBVariant& varValue,
	short nFieldType = DEFAULT_FIELD_TYPE);
void GetFieldValue(short nIndex, CDBVariant& varValue,
	short nFieldType = DEFAULT_FIELD_TYPE);
void GetFieldValue(LPCTSTR lpszName, CString &strValue);
void GetFieldValue(short nIndex, CString &strValue);

可通过字段(列)名称获取当前行中对应字段的值,也可通过字段(列)序号获取字段值。

CRecordset recset(&database);
CString sSql=_T("SELECT * FROM [Sheet1$]");
CString sItem;// 执行查询语句

if (recset.Open(CRecordset::forwardOnly, sSql, CRecordset::readOnly))
{	
	int nRow = 0;
	while (!recset.IsEOF())
	{
		for(int i = 0 ; i < nColCount ; i++)
		{
			//通过字段(列)序号获取字段值
			recset.GetFieldValue(i, sItem);
			std::cout << "第"  <<nRow + 1  << "行第" << i + 1 << "列的值为:" << sItem << std::endl;
		}
		
		//通过字段(列)名称获取当前行中对应字段的值
		recset.GetFieldValue(_T("Id"),sItem);
		std::cout << "第"  <<nRow + 1  << "行字段Id的值为:" << sItem << std::endl;
		nRow++;
		recset.MoveNext();
	}
	recset.Close();
}

四、写Excel文件

1、创建文件

打开Excel文件

一致,将sDsn连接字符串改为

sDsn.Format(_T("DRIVER={%s};DSN='Excel nFiles';READONLY=FALSE;DBQ=%s"), sDriver, sFilePath/*保存Excel文件路径*/)

2、创建Sheet即数据表

使用SQL语言表创建语句创建Sheet及列名,其中列名最好以反单引号括住,以免与SQL关键字混淆,造成运行错误

CString sSql = _T("CREATE TABLE Sheet1 (`Id` NUMBER,`name` TEXT,`age` NUMBER)");
database.ExecuteSQL(sSql);

3、写入数据

使用SQL语言INSERT语句进行数据写入,可带字段名对特定字段写入,也可对所有字段写入,代码如下:

//对指定字段写入
sSql = _T("INSERT INTO Sheet1 (`Id`,`name`) VALUES (1,'daivy')");
database.ExecuteSQL(sSql);
//对所有字段写入
sSql = _T("INSERT INTO Sheet1 VALUES (2,'tony',25)");
database.ExecuteSQL(sSql);

完整代码

CDatabase database;
CString sDsn;
CString sFilePath= _T("d:\\test.xlsx");
CString sDriver = GetExcelDriver();
//创建连接字符串
sDsn.Format(_T("DRIVER={%s};DSN='Excel nFiles';READONLY=FALSE;DBQ=%s"), sDriver, sFilePath/*excel文件保存路径*/);
// 创建或打开文件
if (database.OpenEx(sDsn, CDatabase::noOdbcDialog))
{
	CString sSql = _T("CREATE TABLE Sheet1 (`Id` NUMBER,`name` TEXT,`age` NUMBER)");
	database.ExecuteSQL(sSql);
	//对指定字段写入
	sSql = _T("INSERT INTO Sheet1 (`Id`,`name`) VALUES (1,'daivy')");
	database.ExecuteSQL(sSql);
	//对所有字段写入
	sSql = _T("INSERT INTO Sheet1 VALUES (2,'tony',25)");
	database.ExecuteSQL(sSql);
	database.Close();
	std::cout << "导出数据成功" << std::endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值