【MFC】利用VS2019在MFC中处理excel文件

<学习笔记>利用VS2019在MFC中读写excel文件

包含头文件

#include<afxdb.h>  //用于建立数据库对象,包括CDatabase类
#include <odbcinst.h>
#pragma comment(lib,"odbc32.lib")
#pragma comment(lib,"odbccp32.lib")
#pragma comment(lib,"legacy_stdio_definitions.lib")

获取excel驱动

通过查询的方式使用excel驱动,具体函数如下,函数填入具体使用的驱动名,每台设备可能会有不一样的驱动库,如果想知道自己的驱动都有什么可以在查询循环中加入MessageBox(str)来查看,在本例中主要会用到“Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, .xlsb)”;和“Microsoft Excel Driver (.xls)”。

CString CMyDialog::GetExcelDriver(char* Drivername)//读取EXCEL文件//检索是否安装有Excel驱动
{
	CString sDriver;
	TCHAR szDrivers[4096];
	memset(szDrivers, 0, sizeof(szDrivers));
	WORD wRet = 0;
	// 获取已安装驱动的名称(函数在odbcinst.h里)
	if (SQLGetInstalledDrivers(szDrivers, _countof(szDrivers), &wRet))
	{
		LPTSTR pszDrv = szDrivers;
		// 检索已安装的驱动是否有Excel
		while (*pszDrv)
		{
			CString str = CString(pszDrv);
			CStringA StrA = static_cast<CStringA>(str);
			char* str2 = StrA.GetBuffer();
			//AfxMessageBox(str);//测试
			if (strstr(str2, Drivername) != 0) {

				sDriver = CString(str2);
				return sDriver;
			}
			pszDrv += _tcslen(pszDrv) + 1;
		}
	}
	return _T("");
}

打开excel文件并读取内容

获取excel驱动后,打开打开文件窗口,CDatabase类和CRecordSet类配合使用将excel文件信息在ListControl控件(view=report,变量mList1)上显示。

void CMyDialog::OnBnClickedButton1()
{
	// 打开文件
	CString sDriver = GetExcelDriver("Microsoft Excel Driver (*.xls)"); // Excel安装xls驱动
	//CString sDriver = GetExcelDriver("Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)"); // Excel安装xlsx驱动
	if (sDriver.IsEmpty())
	{
		// 没有发现Excel驱动
		AfxMessageBox(_T("没有安装Excel驱动!"));
		return;
	}

	//打开excel文件窗口
	CString sExcelFile;     // 目标Excel文件
	BOOL IsOpen = true;     //是否打开(否则为保存)    
	CString DefaultType = NULL;   //默认文件拓展名    
	CString DefaultfileName = NULL;         //默认文件名    
	CString TypesFilter = _T("Microsoft Excel Files(*.xls;*.xlsx;*.xlsm;*.xlsb)|*.xls;*.xlsx;*.xlsm;*.xlsb|Worksheet Files (*.xls)|*.xls|Chart Files (*.xlc)|*.xlc|All Files (*.*)|*.*||");   //文件过虑的类型    
	CFileDialog openFileDlg(IsOpen, DefaultType, DefaultfileName, OFN_HIDEREADONLY | OFN_READONLY, TypesFilter, NULL);
	if (openFileDlg.DoModal() == IDOK)
	{
		sExcelFile = openFileDlg.GetPathName();
	}

	TRY
	{
		//准备阶段1
	    CDatabase database;
		CString sSql;
		sSql.Format(CString("DRIVER={%s};DSN='';FIRSTROWHASNAMES=1;READONLY=FALSE;CREATE_DB=\"%s\";DBQ=%s"), sDriver, sExcelFile, sExcelFile);
		// 创建数据库 (既Excel表格文件)
		database.OpenEx(sSql, CDatabase::noOdbcDialog);
		//打开数据库

		//准备阶段2
		/*
		要实现对结果集的数据操作,就要用到CRecordSet类。
		CRecordSet类定义了从数据库接收或者发送数据到数据库的成员变量,CRecordSet类定义的记录集可以是表的所有列,也可以是其中的一列,这是由SQL语句决定的。
		CRecordSet类的成员变量m_hstmt代表了定义该记录集的SQL语句句柄,m_nFields成员变量保存了记录集中字段的个数,m_nParams成员变量保存了记录集所使用的参数个数
		*/
		CRecordset recset(&database);
		//设置读取的查询语句
		CString sql = _T("SELECT * FROM Exceldemo");
		if (!recset.Open(CRecordset::forwardOnly, sql, CRecordset::readOnly))//执行查询语句
			AfxMessageBox(_T("查询失败"));//测试
		short nFields = recset.GetODBCFieldCount();//得到总共多少列
		//if (nFields > 4)
		//	nFields = 4;
		//short nFields = 4;

		//准备阶段3
		mList1.DeleteAllItems();//清空
		int count = mList1.GetItemCount();//获取初始化行的数量
		CString str;

		while (!recset.IsEOF())
		{
			count = mList1.GetItemCount();//获取行的数量
			mList1.InsertItem(count, _T("0"));//插入行
			for (short index = 0; index < nFields; index++)//对每列进行提取,CRecordSet类必须按顺序不能重复或后退
			{
				recset.GetFieldValue(index, str);//获取查询结果
				//AfxMessageBox(str);
				mList1.SetItemText(count, index, str);
			}
			if (str == _T("")||count>=999)//1000行限制
				break;
			recset.MoveNext();
			//移动到下一行
		}
		database.Close();
		CString Message;
		Message.Format(_T("成功打开文件,共读取%i列x%i行"), nFields, count+1);
		MessageBox(Message);
	}
		CATCH(CDBException, e)
	{
		// 数据库操作产生异常时...
		AfxMessageBox(_T("数据库错误") + e->m_strError);
	}
	END_CATCH;
}

如果读取失败可尝试将第一句代码改为“CString sDriver = GetExcelDriver(“Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, .xlsb)");”,注意这里驱动对应的不是文件而是数据格式,即可能文件后缀是.xls而实际使用“CString sDriver = GetExcelDriver("Microsoft Excel Driver (.xls)”);”可能会出现读取失败。

保存excel文件

打开保存文件窗口并获取excel驱动,使用CDatabase类将ListControl控件上的信息写入目标excel文件。

void CMyDialog::OnBnClickedButton3()
{
	// 保存文件
	//打开保存文件窗口
	CFileDialog FileDialog(false, _T("xls"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("Microsoft Excel Files(*.xls;*.xlsx;*.xlsm;*.xlsb)|*.xls;*.xlsx;*.xlsm;*.xlsb|所有文件(*.*)"), NULL);
	if (FileDialog.DoModal() != IDOK)
	{
		return;
	}
	CString sExcelFile = FileDialog.GetPathName();  //选择保存路径名称

	if (::PathFileExists(sExcelFile))
		DeleteFile(sExcelFile);

	CDatabase database;
	CString sDriver = GetExcelDriver("Microsoft Excel Driver (*.xls)");; // Excel安装驱动
	if (sDriver.IsEmpty())
	{
		// 没有发现Excel驱动
		AfxMessageBox(_T("没有安装Excel驱动!"));
		return;
	}

	TRY
	{
		//创建进行存储的字符串
		CString sSql;
		sSql.Format(CString("DRIVER={%s};DSN='';FIRSTROWHASNAMES=1;READONLY=FALSE;CREATE_DB=\"%s\";DBQ=%s"), sDriver, sExcelFile, sExcelFile);
		// 创建数据库 (既Excel表格文件)
		int ItemCount = this->mList1.GetItemCount();
		if (database.OpenEx(sSql, CDatabase::noOdbcDialog))
		{
			sSql.Format(CString("CREATE TABLE Exceldemo (%s number,%s number,%s number,%s number,%s number,%s number,%s number,%s number,%s number)"),
				CString("数据1"),CString("数据2"),CString("数据3"),CString("数据4"),
				CString("差值1"), CString("差值2"), CString("差值3"), CString("差值4"), CString("积分结果"));
			database.ExecuteSQL(sSql);
			for (int i = 0; i <= ItemCount-1; i++) {//索引从0开始所以需要ItemCount-1
				sSql.Format(CString("INSERT INTO Exceldemo (数据1,数据2,数据3,数据4,差值1,差值2,差值3,差值4,积分结果) VALUES ('%lf','%lf','%lf','%lf','%lf','%lf','%lf','%lf','%lf')"),
					_wtof(CString(mList1.GetItemText(i, 0))),
					_wtof(CString(mList1.GetItemText(i, 1))),
					_wtof(CString(mList1.GetItemText(i, 2))),
					_wtof(CString(mList1.GetItemText(i, 3))),
					_wtof(CString(mList1.GetItemText(i, 4))),
					_wtof(CString(mList1.GetItemText(i, 5))),
					_wtof(CString(mList1.GetItemText(i, 6))),
					_wtof(CString(mList1.GetItemText(i, 7))),
					_wtof(CString(mList1.GetItemText(i, 8)))
				);
				database.ExecuteSQL(sSql);
			}
		}
		// 关闭数据库
		database.Close();
		AfxMessageBox(CString("Excel文件写入成功!") + sExcelFile);
	}
		CATCH(CDBException, e)
	{
		// 数据库操作产生异常时...
		AfxMessageBox(_T("数据库错误: ") + e->m_strError);
	}
	END_CATCH;

}

效果图读取结果展示

不足:读取的表内需要设置名称(例子中的表名是Exceldemo),否则读取数据失败。
补充:表名设置方法:找到excel名称管理器(快捷键ctrl+f3)>新建>名称:Exceldemo(例) 范围:工作簿 引用位置:自选>确定

相关推荐

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:1024 设计师:我叫白小胖 返回首页

打赏作者

supriorboy

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值