// ReadWriteExcelDlg.cpp: 实现文件
//
#include "pch.h"
#include "framework.h"
#include "ReadWriteExcel.h"
#include "ReadWriteExcelDlg.h"
#include "afxdialogex.h"
#include <afxdb.h> //数据库头文件
#include <odbcinst.h> //odbc头文件
#pragma comment(lib,"odbc32.lib")
#pragma comment(lib,"odbccp32.lib")
#pragma comment(lib,"legacy_stdio_definitions.lib")
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CReadWriteExcelDlg 对话框
CReadWriteExcelDlg::CReadWriteExcelDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_READWRITEEXCEL_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CReadWriteExcelDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CReadWriteExcelDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &CReadWriteExcelDlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &CReadWriteExcelDlg::OnBnClickedButton2)
END_MESSAGE_MAP()
// CReadWriteExcelDlg 消息处理程序
BOOL CReadWriteExcelDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CReadWriteExcelDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CReadWriteExcelDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CReadWriteExcelDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CReadWriteExcelDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
CDatabase database;
CString sSql;
CString sItem1, sItem2;
CString sDsn;
//CString sFile = L"d:\\demo.xls"; // 将被读取的Excel文件名
CString sFile = L"demo.xls";
CString sDriver;
// 检索是否安装有Excel驱动 "Microsoft Excel Driver (*.xls)"
sDriver = GetExcelDriver();
if (sDriver.IsEmpty())
{
// 没有发现Excel驱动
AfxMessageBox(_T("没有安装Excel驱动!"));
return;
}
// 创建进行存取的字符串,此操作只用于打开excel文件 不具备创建新文件的功能,如果不存在该文件则报错。
sDsn.Format(L"ODBC;DRIVER={%s};DSN='';DBQ=%s", sDriver, sFile);
TRY
{
// 打开数据库(既Excel文件)
database.Open(NULL, false, false, sDsn);
CRecordset recset(&database);//创建用于操作数据文件中记录的对象
// 设置读取的查询语句.
//特别注意此处的[Sheet1$]格式,其中Sheet1是demo.xls文件中的一个数据表,普通excel文件中往往不具备表结构,而通过odbc创建的excel文件具备表结构,这就是网上大多数无法用odbc打开普通excel文件的原因所在(将相应的数据表设置会具备表功能的结构也可以通过直接使用Sheet1打开,具体方法百度即可),直接使用[Sheet1$]这种格式即忽略了文件中是否具有表结构,直接将指定的表名所对应的表当作数据表进行读取操作。
sSql = "SELECT * FROM [Sheet1$]";
// 执行查询语句
recset.Open(CRecordset::forwardOnly, sSql, CRecordset::readOnly);
// 获取查询结果
//-----------------------------------------------------------
short nFields = recset.GetODBCFieldCount();//得到总共多少列
//准备阶段3
//mList1.DeleteAllItems();//清空
//int count = mList1.GetItemCount();//获取初始化行的数量
//CString str;
//此处存在问题是利用该循环会读到数据最后一行的下一行(即多读一行),IsEOF()函数功能是判断指针是否指到文件末尾,当指到最后一行时该函数返回false,只有当再往下读取时,发现文件已经到结尾了,才会将标志返回true。这也就是为什么使用IsEOF()会出多现读一行的原因。至于解决方法可以利用循环或者条件判断跳出语句等等方法解决!
CString StrInfo = L"";
int Hcount = 0;
while (!recset.IsEOF())
{
for (int i = 0; i < recset.GetODBCFieldCount(); i++)
{
CString Str;
recset.GetFieldValue(i, Str); //读取某行的第i列单元格数据
StrInfo += Str + L" ";
}
StrInfo += "\r\n";
Hcount++;
recset.MoveNext(); //移动到下一行
}
MessageBox(StrInfo);
// 关闭数据库
database.Close();
CString Message;
Message.Format(_T("成功打开文件,共读取%i列x%i行"), nFields, Hcount);
MessageBox(Message);
}
CATCH(CDBException, e)
{
// 数据库操作产生异常时...
AfxMessageBox(L"数据库错误: " + e->m_strError);
}
END_CATCH;
}
// 读取EXCEL文件//检索是否安装有Excel驱动
CString CReadWriteExcelDlg::GetExcelDriver()
{
// TODO: 在此处添加实现代码.
CString sDriver;
TCHAR szDrivers[4096];
memset(szDrivers, 0, sizeof(szDrivers));
WORD wRet = 0;
// 获取已安装驱动的名称(函数在odbcinst.h里)
if (SQLGetInstalledDrivers(szDrivers, _countof(szDrivers), &wRet))
{
LPTSTR pszDrv = szDrivers;
while (*pszDrv)
{
CString str = CString(pszDrv);
CStringA StrA = static_cast<CStringA>(str);
char* str2 = StrA.GetBuffer();
//LPTSTR -> char*
//MessageBox(pszDrv);
if (strstr(str2, "Excel") != 0) {
sDriver = CString(str2);
return sDriver;
}
pszDrv += _tcslen(pszDrv) + 1;
}
}
}
void CReadWriteExcelDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
CDatabase DB;
CString sDriver = GetExcelDriver();
if (sDriver.IsEmpty())
{
MessageBox(L"Excel driver is not installed!");
return;
}
CString sPath = _T(".\\WriteDemo.xls");
CString sSQL;
sS
评论5