首页 > 其他分享 >一步一步地教你实现OLE读取EXCEL(一)

一步一步地教你实现OLE读取EXCEL(一)

时间:2022-11-03 22:00:13浏览次数:53  
标签:return name 一步 excel 地教 EXCEL long file iSheet


OLE实现EXCEL读取的动态链接库的具体步骤

1.环境搭建:

我们需要什么环境背景呢?我用的是VS2015 + Microsoft Excel 2015,这里强调一下OLE不能在WPS上进行,因为OLE需要调用微软的基础类库(MFC),所以我们需要用到Excel软件,如果您用的是WPS,请出门右转!

2.具体步骤:

2.1创建工程:


我们要实现一个可以实现excel读取的动态链接库,当需要读取EXCEL时,直接加载dll即可实现excel读取,看图!


一步一步地教你实现OLE读取EXCEL(一)_ico


选择MFC DLL,取名ExcelRead,点击确定。这样我们就在G盘生成了一个动态链接库的工程。



一步一步地教你实现OLE读取EXCEL(一)_sed_02



一路下一步,记得在自动化的前面打上勾,点击完成。


一步一步地教你实现OLE读取EXCEL(一)_加载_03


默认工程是debug和x86格式的,因为excel是64位的,所以我们将工程调整为x64,如果工程按照x86编译,会出现10处报错,例如:LPWSTR不能转换为char *类型,1.exe已退出等等,主要原因在于32位指令与64位指令的字符集是不一样的,32位指令用的是ASCII码指令字,64位指令的字符集是宽字符集,具体原因请百度


一步一步地教你实现OLE读取EXCEL(一)_sed_04


在项目名处右键,点击添加->类。


一步一步地教你实现OLE读取EXCEL(一)_ico_05


点击添加MFC中的typelib类中的MFC类,点击添加。


一步一步地教你实现OLE读取EXCEL(一)_ico_06


在可用的类型库下拉框选择Microsoft Excel 16.0 Object Library,之后将图上6个类添加进去,点击完成!


一步一步地教你实现OLE读取EXCEL(一)_加载_07


红色的框框里面是新生成的头文件,有6个头文件,分别定义了六个OLE的类。之后我们将绿色框里面的代码注释掉,红框里面的6个头文件都有这句代码,统统注释掉,否则,,,,呵呵,120个编译错误会等着你。。。


一步一步地教你实现OLE读取EXCEL(一)_加载_08


在stdafx.h里面添加绿色框框里面的代码。之后你会看见下图。


一步一步地教你实现OLE读取EXCEL(一)_ico_09


以CApplication.h为例,红色波浪线消失了有木有

,把#import "C:\\Program Files (x86)\\Microsoft Office\\Root\\Office16\\EXCEL.EXE" no_namespace那句注释掉之后界面如上图所示!

之后我们创建一个头文件以实现对OLE读取EXCEL类的定义。创建一个CExcelFileRead.h,代码如下:


#pragma once
// 用于OLE方式读取Excel文件
class CReadExcelFile //对一个excel文件的读取操作
{
private:
static CApplication excel_application; //EXCEL进程实例,只有一个
CWorkbooks excel_books; // workbook集合(多个文件时)
CWorkbook excel_work_book; // 当时使用的workbook
CWorksheets excel_sheets; // worksheet集合
CWorksheet excel_work_sheet; // 当前使用的worksheet
CRange excel_current_range; // 当前操作的区域
CString open_excel_file; // 打开的Excel文件名称

BOOL OpenFileFlag; // 打开Excel文件是否失败

protected:
// 使用某个sheet
BOOL LoadSheet(long iSheet);
BOOL LoadSheet(const char* sheet_name);

public:
// 构造函数:打开Excel文件
CReadExcelFile(const char* file_name);
// 析构函数:关闭Excel文件
~CReadExcelFile();
// 判断是否打开成功
BOOL IsOpenSuccess();
// 初始化Excel OLE
static BOOL InitExcel();
// 释放Excel OLE
static void ReleaseExcel();
// 取得打开的文件名称
CString GetCurrentFileName();
// 得到Sheet的总数
int GetSheetCount();
// 取得某个Sheet的名称
CString GetSheetName(long iSheet);
// 取得行的总数
int GetRowCount(long iSheet);
// 取得列的总数
int GetColCount(long iSheet);
// 根据Sheet名称获得Sheet标号
int GetSheetIndex(const char * sheet_name);
// 得到一个Cell的String
CString GetCellString(long iSheet, long iRow, long iCol);
// 得到一个Cell的Int
int GetCellInt(long iSheet, long iRow, long iCol);
// 得到一个Cell的double
double GetCellDouble(long iSheet, long iRow, long iCol);
// 检查一个Cell是否空
BOOL IsCellEmpty(long iSheet, long iRow, long iCol);
// 检查一个Cell是否是字符串
BOOL IsCellString(long iSheet, long iRow, long iCol);
// 检查一个Cell是否是数值
BOOL IsCellInt(long iSheet, long iRow, long iCol);
// 取得列的名称(如第27列为AA)
static CString GetColName(long iCol);
};

创建头文件的实现文件 CExcelFileRead.cpp中定义以下代码。


#include "stdafx.h"
#include "CExcelFileRead.h"

COleVariant covTrue((short)TRUE), covFalse((short)FALSE), covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
// Excel App初始化
CApplication CReadExcelFile::excel_application;
// 初始化Excel OLE
BOOL CReadExcelFile::InitExcel()
{
// 初始化COM库
CoInitialize(NULL);
// 初始化Excel
if (!excel_application.CreateDispatch("Excel.Application", NULL))return FALSE;
excel_application.put_DisplayAlerts(FALSE); // 屏蔽警告
return TRUE;
}
// 释放Excel OLE
void CReadExcelFile::ReleaseExcel()
{
excel_application.ReleaseDispatch();
excel_application.Quit();
excel_application = NULL;
}
// 构造函数
CReadExcelFile::CReadExcelFile(const char * file_name)
{
// 连接excel app
excel_books.AttachDispatch(excel_application.get_Workbooks());
// 打开文件并初始化excel_work_book
LPDISPATCH lpDisp = NULL;
TRY
{
lpDisp = excel_books.Open(file_name, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional);
}
CATCH(COleDispatchException, e)
{
AfxMessageBox(e->m_strDescription);
OpenFileFlag = FALSE;
return;
}
END_CATCH
OpenFileFlag = TRUE;
excel_work_book.AttachDispatch(lpDisp);
// 得到所有的sheets并初始化excel_sheets
excel_sheets.AttachDispatch(excel_work_book.get_Worksheets());
// 得到活动的工作表并初始化excel_work_sheet
excel_work_sheet.AttachDispatch(excel_work_book.get_ActiveSheet());
// 初始化当前的操作区域excel_current_range
excel_current_range.AttachDispatch(excel_work_sheet.get_Cells());
// 设置当前的文件名
open_excel_file = file_name;
}
// 析构函数:关闭文件
CReadExcelFile::~CReadExcelFile()
{
excel_books.Close();
}
// 判断是否打开成功
BOOL CReadExcelFile::IsOpenSuccess() { return OpenFileFlag; }
// 返回打开的Excel文件名称
CString CReadExcelFile::GetCurrentFileName()
{
return open_excel_file;
}
// 加载某个Sheet,通过index
BOOL CReadExcelFile::LoadSheet(long iSheet)
{
if (iSheet > excel_sheets.get_Count())return FALSE;
// 如果iSheet当前已经加载
if (iSheet == excel_work_sheet.get_Index())return TRUE;
// 释放先前的
excel_current_range.ReleaseDispatch();
excel_work_sheet.ReleaseDispatch();
// 加载iSheet
LPDISPATCH lpDisp = excel_sheets.get_Item(COleVariant((long)iSheet));
if (!lpDisp)return FALSE;
excel_work_sheet.AttachDispatch(lpDisp);
excel_current_range.AttachDispatch(excel_work_sheet.get_Cells());
return TRUE;
}
// 加载某个Sheet,通过名称
BOOL CReadExcelFile::LoadSheet(const char * sheet_name)
{
// 如果iSheet当前已经加载
if (excel_work_sheet.get_Name() == sheet_name)return TRUE;
// 释放先前的
excel_current_range.ReleaseDispatch();
excel_work_sheet.ReleaseDispatch();
// 加载iSheet
LPDISPATCH lpDisp = excel_sheets.get_Item(COleVariant(sheet_name));
if (!lpDisp)return FALSE;
excel_work_sheet.AttachDispatch(lpDisp);
excel_current_range.AttachDispatch(excel_work_sheet.get_Cells());
return TRUE;
}
// 获得sheet数目
int CReadExcelFile::GetSheetCount()
{
return excel_sheets.get_Count();
}
// 获得某个Sheet的名称
CString CReadExcelFile::GetSheetName(long iSheet)
{
// 加载iSheet
if (!LoadSheet(iSheet))return CString();
return excel_work_sheet.get_Name();
}
// 获得某个Sheet的row数目
int CReadExcelFile::GetRowCount(long iSheet)
{
// 加载iSheet
if (!LoadSheet(iSheet))return 0;
// 获取使用范围usedRange,获取行range
CRange usedRange; usedRange.AttachDispatch(excel_work_sheet.get_UsedRange());
CRange range; range.AttachDispatch(usedRange.get_Rows());
// 获得数目
int count = range.get_Count();
// 释放
usedRange.ReleaseDispatch();
range.ReleaseDispatch();
// 返回
return count;
}
// 获得某个Sheet的column数目
int CReadExcelFile::GetColCount(long iSheet)
{
// 加载iSheet
if (!LoadSheet(iSheet))return 0;
// 获取使用范围usedRange,获取行range
CRange usedRange; usedRange.AttachDispatch(excel_work_sheet.get_UsedRange());
CRange range; range.AttachDispatch(usedRange.get_Columns());
// 获得数目
int count = range.get_Count();
// 释放
usedRange.ReleaseDispatch();
range.ReleaseDispatch();
// 返回
return count;
}
// 根据Sheet的名称获得Sheet的index
int CReadExcelFile::GetSheetIndex(const char * sheet_name)
{
if (!LoadSheet(sheet_name))return -1;
return excel_work_sheet.get_Index();
}
// 获得某个Sheet的字符串Cell
CString CReadExcelFile::GetCellString(long iSheet, long iRow, long iCol)
{
// 加载iSheet
if (!LoadSheet(iSheet))return CString();
// 读取
CRange range; range.AttachDispatch(excel_current_range.get_Item(COleVariant((long)iRow), COleVariant((long)iCol)).pdispVal);
COleVariant vResult = range.get_Value2();
range.ReleaseDispatch();
// 分析vResult
CString str;
if (vResult.vt == VT_BSTR)str = vResult.bstrVal; // 字符串
else if (vResult.vt == VT_INT)str.Format(_T("%d"), vResult.pintVal); // 整数
else if (vResult.vt == VT_R8)str.Format(_T("%0.0f"), vResult.dblVal); // 8字节的整数
else if (vResult.vt == VT_DATE) // 时间格式
{
SYSTEMTIME st; VariantTimeToSystemTime(vResult.date, &st);
CTime tm(st); str = tm.Format("%Y-%m-%d");
}
else if (vResult.vt == VT_EMPTY)str = ""; // 空的单元格
else str = "";
return str;
}
// 获得某个Sheet的整数Cell
int CReadExcelFile::GetCellInt(long iSheet, long iRow, long iCol)
{
// 加载iSheet
if (!LoadSheet(iSheet))return 0;
// 读取
CRange range; range.AttachDispatch(excel_current_range.get_Item(COleVariant((long)iRow), COleVariant((long)iCol)).pdispVal);
COleVariant vResult = range.get_Value2();
range.ReleaseDispatch();
// 分析vResult
int num = static_cast<int>(vResult.dblVal);
return num;
}
// 获得某个Sheet的浮点数Cell
double CReadExcelFile::GetCellDouble(long iSheet, long iRow, long iCol)
{
// 加载iSheet
if (!LoadSheet(iSheet))return 0.0;
// 读取
CRange range; range.AttachDispatch(excel_current_range.get_Item(COleVariant((long)iRow), COleVariant((long)iCol)).pdispVal);
COleVariant vResult = range.get_Value2();
range.ReleaseDispatch();
// 分析vResult
double rtn_value = 0.0;
if (vResult.vt == VT_R8)rtn_value = vResult.dblVal;
return rtn_value;
}
// 检查Cell是否空
BOOL CReadExcelFile::IsCellEmpty(long iSheet, long iRow, long iCol)
{
// 加载iSheet
if (!LoadSheet(iSheet))return TRUE;
// 读取
CRange range; range.AttachDispatch(excel_current_range.get_Item(COleVariant((long)iRow), COleVariant((long)iCol)).pdispVal);
COleVariant vResult = range.get_Value2();
range.ReleaseDispatch();
// 分析vResult
if (vResult.vt == VT_EMPTY)return TRUE;
else return FALSE;
}
// 检查Cell是否是字符串
BOOL CReadExcelFile::IsCellString(long iSheet, long iRow, long iCol)
{
// 加载iSheet
if (!LoadSheet(iSheet))return FALSE;
// 读取
CRange range; range.AttachDispatch(excel_current_range.get_Item(COleVariant((long)iRow), COleVariant((long)iCol)).pdispVal);
COleVariant vResult = range.get_Value2();
//VT_BSTR标示字符串
if (vResult.vt == VT_BSTR)return TRUE;
return FALSE;
}
// 检查Cell是否是int
BOOL CReadExcelFile::IsCellInt(long iSheet, long iRow, long iCol)
{
// 加载iSheet
if (!LoadSheet(iSheet))return FALSE;
// 读取
CRange range; range.AttachDispatch(excel_current_range.get_Item(COleVariant((long)iRow), COleVariant((long)iCol)).pdispVal);
COleVariant vResult = range.get_Value2();
// 检查
if (vResult.vt == VT_INT || vResult.vt == VT_R8)return TRUE;
return FALSE;
}
// 取得列的名称(如第27列为AA)
CString CReadExcelFile::GetColName(long iCol)
{
// 初始化column_name
char column_name[64];
// 分析iCol
size_t str_len = 0; while (iCol > 0)
{
int num_data = iCol % 26;
iCol /= 26;
if (num_data == 0)
{
num_data = 26;
iCol--;
}
column_name[str_len] = (char)((num_data - 1) + 'A');
str_len++;
}
column_name[str_len] = '\0';
// 反转
_strrev(column_name);
// 返回
return CString(column_name);
}

创建一个对外接口头文件DLL_API.h文件,代码如下:

#pragma once
//--------------------------------------------------------------------//
// DLL对外接口函数:
// 1.完成Excel OLE的初始化
// 2.给出要读取的文件名、Sheet标号、列数、行数等相关信息进行读取;
// 3.完成Excel OLE的释放
//--------------------------------------------------------------------//
// 维护函数:
// 维护函数实现从读取函数到CReadExcel类对象的过程实现和维护。在得到
// 用户调用的读取函数之后,维护函数判断该文件是否已经打开:
// 1.如果已经打开,那么到OpenFileList中找到对应的CReadExcelFile类的
// 指针,并进行后续的操作;
// 2.如果没有打开,那么申请一个新的CReadExcelFile类并将其存入打开文
// 件列表OpenFileList,之后进行后续操作;
//--------------------------------------------------------------------//
#pragma once
#include "CExcelFileRead.h"
#include<vector>
#define DLL_API extern "C" __declspec(dllexport)

using namespace std;

//----DLL全局变量:读取文件记录---------------------------------------//
vector<CReadExcelFile*> OpenFileList;

//----DLL对外接口函数-------------------------------------------------//
// 完成Excel OLE的初始化
DLL_API bool Excel_Init();
// 完成Excel OLE的释放
DLL_API void Excel_Release();
// 得到某文件Sheet的总数
DLL_API int get_sheets_count(string &file_name);
// 得到某文件某个Sheet的名称
DLL_API string get_sheet_name(string &file_name, long iSheet);
// 得到某个文件某个Sheet的行数
DLL_API int get_rows_count(string &file_name, long iSheet);
// 得到某个文件某个Sheet的列数
DLL_API int get_cols_count(string &file_name, long iSheet);
// 根据Sheet名称获得Sheet标号
DLL_API int get_sheet_index(string &file_name, string &sheet_name);
// 得到某个文件某个Sheet某个Cell(字符串)
DLL_API string get_cell_string(string &file_name, long iSheet, long iRows, long iCols);
// 得到某个文件某个Sheet某个Cell(整数)
DLL_API int get_cell_int(string &file_name, long iSheet, long iRows, long iCols);
// 得到某个文件某个Sheet某个Cell(浮点数)
DLL_API double get_cell_double(string &file_name, long iSheet, long iRows, long iCols);
// 判断Cell是否空
DLL_API bool IsCellEmpty(string &file_name, long iSheet, long iRows, long iCols);


//----维护函数,对外不可见---------------------------------------------//
// 在OpenFileList中寻找某文件的index,不存在返回-1
int FindFileIndexInList(string &file_name);
// 总维护过程
CReadExcelFile *Maintain(string &file_name);
// 释放Excel OLE时要清空列表,析构其中所有CReadExcelFile类
void CloseAllFile();


#include "stdafx.h"
#include "DLL_API.h"

//--维护函数的实现----------------------------------------------------//
// 在OpenFileList中寻找某文件的index,不存在返回-1
int FindFileIndexInList(string &file_name)
{
for (int index = 0; index < OpenFileList.size(); index++)
if (OpenFileList.at(index)->GetCurrentFileName() == file_name.c_str())
return index;
return -1;
}
// 总维护过程
CReadExcelFile *Maintain(string &file_name)
{
// 在OpenFileList中寻找某文件
int index = FindFileIndexInList(file_name);
// 如果找到,返回指针
if (index != (-1))return OpenFileList.at(index);
// 如果未找到,新打开一个文件
CReadExcelFile *new_file = new CReadExcelFile(file_name.c_str());
// 若打开文件失败,关闭所有文件,释放Excel OLE并退出
if (!(new_file->IsOpenSuccess()))
{
delete new_file;
CloseAllFile();
Excel_Release();
exit(1);
}
// 否则,将新文件存入打开文件列表
OpenFileList.push_back(new_file);
return new_file;
}
// 释放Excel OLE时要清空列表,析构其中所有CReadExcelFile类
void CloseAllFile()
{
for (int index = 0; index < OpenFileList.size(); index++)
delete OpenFileList.at(index);
OpenFileList.clear();
}


//--DLL对外接口函数的实现---------------------------------------------//
// 完成Excel OLE的初始化
bool Excel_Init()
{
if (CReadExcelFile::InitExcel())return true;
else return false;
}
// 完成Excel OLE的释放
void Excel_Release()
{
CloseAllFile();
CReadExcelFile::ReleaseExcel();
}
// 得到某文件Sheet的总数
int get_sheets_count(string &file_name)
{
CReadExcelFile *file = Maintain(file_name);
return file->GetSheetCount();
}
// 得到某文件某个Sheet的名称
string get_sheet_name(string &file_name, long iSheet)
{
CReadExcelFile *file = Maintain(file_name);
return file->GetSheetName(iSheet);
}
// 得到某个文件某个Sheet的行数
int get_rows_count(string &file_name, long iSheet)
{
CReadExcelFile *file = Maintain(file_name);
return file->GetRowCount(iSheet);
}
// 得到某个文件某个Sheet的列数
int get_cols_count(string &file_name, long iSheet)
{
CReadExcelFile *file = Maintain(file_name);
return file->GetColCount(iSheet);
}
// 根据Sheet名称获得Sheet标号
int get_sheet_index(string &file_name, string &sheet_name)
{
CReadExcelFile *file = Maintain(file_name);
return file->GetSheetIndex(sheet_name.c_str());
}
// 得到某个文件某个Sheet某个Cell(字符串)
string get_cell_string(string &file_name, long iSheet, long iRows, long iCols)
{
CReadExcelFile *file = Maintain(file_name);
return file->GetCellString(iSheet, iRows, iCols);
}
// 得到某个文件某个Sheet某个Cell(整数)
int get_cell_int(string &file_name, long iSheet, long iRows, long iCols)
{
CReadExcelFile *file = Maintain(file_name);
return file->GetCellInt(iSheet, iRows, iCols);
}
// 得到某个文件某个Sheet某个Cell(浮点数)
double get_cell_double(string &file_name, long iSheet, long iRows, long iCols)
{
CReadExcelFile *file = Maintain(file_name);
return file->GetCellDouble(iSheet, iRows, iCols);
}
// 判断Cell是否空
bool IsCellEmpty(string &file_name, long iSheet, long iRows, long iCols)
{
CReadExcelFile *file = Maintain(file_name);
return file->IsCellEmpty(iSheet, iRows, iCols);
}


下图为本动态链接库工程的文件结构:



一步一步地教你实现OLE读取EXCEL(一)_加载_10











标签:return,name,一步,excel,地教,EXCEL,long,file,iSheet
From: https://blog.51cto.com/u_13121994/5821252

相关文章

  • 3.9 使用Python操作Excel表格的样式1
    #获取表格单元格,修改字体样式修改字体样式 Font(name=字体名称,size=字体大小,bold=是否加粗,italic=是否斜体,color=字体颜色)获取表格中字体的样式cell.font.属性......
  • .Net Excel 的帮助方法
    ///<summary>///读取Excel流到DataSet///</summary>///<paramname="stream">Excel流</param>///<paramname="dict">......
  • MySQL导出表数据为Excel文件时变成E+15【原创】
    如标题所示,因为Excel数据格式变成E+15导致查出的数据不准确。上午百度也没搜出好的方法。想到了一个笨办法,先将文件导成txt,然后用UE列模式在数据前加一列单引号,在黏贴到Ex......
  • 转:Excel教程:excel位数不足补0公式的两种写法
    内容提要:关于excel位数不足补0公式,一般是使用text函数来占位。比如excel数字前面补0成为八位,就可以使用这个方法。今天给大家分享excel位数不足补0公式的两种写法,分别使用......
  • 高德地图搜索结果如何导出成excel里?
    前段时间,根据朋友的要求,开发了地图里的商家采集工具。地图商家如何导出?电话如何导出EXCEL?现在很多做销售工作的思路都开阔了,从地图上直接找商家推销。但是普遍反映一个......
  • 转:关于Excel中截取字符串操作,这一篇就足够了
    在数据分析的时候,一些数需要经过加工之后才能使用。数据分析最常用就是对单元格数据的提取,这就要求我们要对单元格进行加工,从而更好的应用这些数据。  Left函数:......
  • c# winform使用NOPI读取Excel读取图片
    需求:在Winform使用NOPI做导入时候,需要导入数据的同时导入图片。虽然代码方面不适用(我好像也没仔细看过代码),但是感谢大佬给了灵感http://www.wjhsh.net/IT-Ramon-p-13100......
  • 盘点一个使用Python实现Excel数理统计的实战问题
    大家好,我是皮皮。一、前言前几天在小小明大佬的Python交流群中遇到一个粉丝问了一个使用Python实现Excel数理统计的实战问题,觉得还挺有用的,这里拿出来跟大家一起分享下。......
  • #yyds干货盘点#JS 解析 excel 文件
    JS解析excel文件分为如下几步:使用 ​​js​​ 解压缩 ​​excel​​ 文件获取到其中的 ​​sheet​​ 文件内容,然后将 ​​xml​​ 数据解析出来将数据转换成我们想......
  • Excel折线图设置坐标轴起点不为0
     ......