C++操作Excel学习笔记
⼀:
【当前博⽂转载⾃】
C++读取Excel⽂件⽅式⽐较
C++读取Excel的XLS⽂件的⽅法有很多,但是也许就是因为⽅法太多,⼤家在选择的时候会很疑惑。
由于前两天要做导表⼯具,⽐较了常⽤的⽅法,总结⼀下写个短⽂,
1.OLE的⽅式
这个⼤约是最常⽤的⽅式,这个⽅式其实启动了⼀个EXCEL的进程在背后读写EXCEL⽂件,这个⽅式的最⼤好处是什么事情都能做。包括设置EXCEL的格式,增加删除Sheet,读写单元格,等等。功能⼏乎是最全的,⽽且使⽤起来也不是特别的难。
其基本⽅法都是使⽤导出的.h⽂件进⾏OLE操作,但是由于OLE的接⼝说明⽂档不多,想⾮常完美的使⽤她们也不是太容易,好在例⼦也很多。
⽹上普遍认为OLE速度慢,EXCEL的OLE读写⽅式也基本⼀样。但是读取速度可以改进,如果在读取的加载整个Sheet的Range的全部数据,⽽不是⼀个个单元格读取,那么速度还是相对不错。想想原理也很简单,整体读取减少了OLE的交互次数。OLE的写⼊⽅式⼀般只能⼏个进⾏⽐较⽅便,所以速度可能要快很多。
我⾃⼰的亲⾝体会是,⼀个EXCEL⽂件,100多列的字段,如果采⽤⼀个个单元格的读取⽅式,1s⼤约3条左右的记录,如果整体读取,速度可以提⾼⼏⼗倍。
OLE读写EXCEL⽅式功能很强⼤,读取速度还可以,但写⼊速度不⾼,当然这个⽅式不可能移植的,⽽且你必须安装了EXCEL。
2.Basic EXCEL ⽅式
这是CodeProject上的⼀个推荐开源⼯程了,
作者是基于EXCEL的⽂件格式进⾏的处理。但是为什么叫Basic EXCEL呢。
他不⽀持很多东西,公式,⽂件格式,表格合并等(有⼈说中⽂⽀持也不好),所以可以认为他只⽀持最基本的EXCEL表格,
我⾃⼰的尝试是如果这个EXCEL⽂件有其他元素(公式,格式等),使⽤Basic EXCEL读取会失败。
OLE读写EXCEL⽅式功能⽐较弱,由于是直接根据⽂件格式操作,读写速度都不错,你也不需要按照EXCEL,另外这个⽅式是可以移植的,但是有⼀些成本,其代码⽐较晦涩难懂,⽽且没有注释,另外即使在Windows平台上,告警也很多。
3.Sourceforge 上的⼏个EXCEL库。
Sourceforge 上有⼏个开源的的EXCEL库,但是完善的不多,有的是为了PHP读写EXCEL准备的,包括libXLS,XLSlib,SmartEXCEL 等。我下载了⼏个实验了⼀下,在Widonws都没有编译成功。也罢了。
4.ODBC的⽅式
这个亲⾝没有尝试过,但是按照原理,应该只能读写。
速度吗,ODBC的速度本来就是出名的慢了。
值得⼀提的是Basic EXCEL的作者原来在CodeProject上有⼀个给予ODBC⽅式的封装CSpreadSheet 。如果有兴趣,⼤家可以去看看。其实内⼼还是很佩服这个作者的。
5.ADO的⽅式
ADO的⽅式听说应该就是使⽤OLEDB的⽅式。和OLE的⽅式应该没有本质区别。我看了看例⼦也和OLE很像
6.LibXL
LibXL 是⼀个收费的EXCEL的库。
按照他的说明,他可以不依赖EXCEL读取XLS⽂件。包括设置格式等。看例⼦操作应该很简单。但是是否可以移植到Linux平台,我估计难度也不⼩。呵呵。
由于要收费,没有法⼦测试了。
7.⽹上⼀些号称不⽤OLE读取EXCEL例⼦
初步看了⼀下,这个应该是⽹上探索EXCEL格式⽂档的例⼦。可以实际操作的⽅式不强。
⼆:
【当前博⽂转载⾃】
VS2010 C++ 操纵Excel表格的编程实现
经由过程VC实现对Excel表格的操纵的办法有多种,如:经由过程ODBC数据库实现,经由过程解析Excel表格⽂件,经由过程OLE/COM的实现。本⽂⾸要研究经由过程OLE/COM实现对Excel表格的操纵。
本⽂源码的应⽤景象申明:
Windows XP SP3
Microsoft Visual Studio 2010
Microsoft Office Excel 2007
1、添加OLE/COM⽀撑。
起⾸,应⽤法度必须添加对OLE/COM的⽀撑,才⼲导⼊OLE/COM组件。
本⽂应⽤的是MFC对话框法度,在创建⼯程的领导中选中Automation选项即可为法度主动添加响应的头⽂件和OLE库初始化代码。
经由过程查看源代码,可以知道在stdafx.h的头⽂件中,添加了OLE/COM很多类所需添加的头⽂件。
#include // MFC 主动化类
同时,在应⽤法度类的InitInstance函数中,添加了OLE/COM的初始化代码,如下所⽰:
// 初始化 OLE 库
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
2、导⼊并封装Excel中的接⼝
Excel作为OLE/COM库插件,定义好了各类交互的接⼝,这些接⼝是跨说话的接⼝。VC可以经由过程导⼊这些接⼝,并经由过程接⼝来
对Excel的操纵。
因为本⽂只关怀对Excel表格中的数据的读取,⾸要存眷⼏
个_Application、Workbooks、_Workbook、Worksheets、_Worksheet、Range等⼏个接⼝。Excel的各类接⼝的属性、办法可以经由过
程MSDN的Office Development进⾏查询。
VS2010导⼊OLE/COM组件的接⼝的步调为:Project->Class Wizard->Add Class->MFC Class From TypeLib,先选择要导⼊的组件地点的路径,即地点的路径,然后再选择要导⼊的Excel类型库中的接⼝。
在完成接⼝导⼊后,VS2010将主动为导⼊的接⼝创建响应的实现类,⽤于对接⼝属性和办法的实现。因为标准的C++没有属性接见器,只能添加⼀个两个存取函数来实现对属性的接见,经由过程在属性名称前加上get_和put_前缀分别实现对属性的读写操纵。即,由VC主动完成C++类对接⼝的封装。
⽂所导⼊的接⼝对应的类和头⽂件的申明如下所⽰:
Excel接⼝导⼊类头⽂件申明
_Application CApplicaton Application.h Excel应⽤法度。
Workbooks CWorkbooks Workbooks.h⼯作簿的容器,⾥⾯包含了Excel应⽤法度打开的所有⼯作簿。
_Workbook CWorkbook Workbook.h单个⼯作簿。
Worksheets CWorksheets Worksheets.h单个⼯作簿中的Sheet表格的容器,包含该⼯作簿中的所有Sheet。
_Worksheet CWorksheet Worksheet.h单个Sheet表格。
Range CRange Range.h必然命量的单位格,可对单位格进⾏单个或多个单位格进⾏操纵。
3、导⼊Excel的全部类型库
接⼝对应类只是对接⼝的属性和办法进⾏了封装,⽽Excel中的数据类型,如列举类型却并为并不克不及应⽤,是,为了更便利的操
纵Excel,还须要导⼊Excel的数据类型。
经由过程查看导⼊接⼝对应的头⽂件可以发明,在所有导⼊接⼝的头⽂件中,都⾢有这么⾏:
#import "D:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE" no_namespace
这⾏代码的感化是导⼊Excel全部类型库到⼯程中。
由VS2010主动产⽣的导⼊代码存在以下⼏个题⽬:
(1)若是导⼊了多个接⼝,每个头⽂件都⾢把类型库导⼊⼀次,若是引⽤多个头⽂件,会导致类型库反复导⼊。
(2)Excel类型库中有些类型会跟MFC类库的某些类型冲突。
(3)Excel类型库的某些类型跟其他Office和VB的某些库相⼲,若是不导⼊相⼲库,将导致这些类型⽆法应⽤。。
以上三点题⽬的解决办法如下:
(1)仅在_Application接⼝对应头⽂件中导⼊Excel类型库。
(2)对冲突的类型进⾏重定名。
(3)在导⼊Excel类型库之前,先导⼊Office和VB的相⼲库。
更改后的导⼊类型库的代码如下:
#import "C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE12\\MSO.DLL" \
rename("RGB", "MSORGB") \
rename("DocumentProperties", "MSODocumentProperties")
using namespace Office;
#import "C:\\Program Files\\Common Files\\Microsoft Shared\\VBA\\VBA6\\VBE6EXT.OLB"
using namespace VBIDE;
#import "D:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE" \
rename("DialogBox", "ExcelDialogBox") \
rename("RGB", "ExcelRGB") \
rename("CopyFile", "ExcelCopyFile") \
rename("ReplaceText", "ExcelReplaceText") \
no_auto_exclude
Using namesapce Excel;
编译法度后,会在Debug或Release⽬次下⽣成三个⽂件mso.tlh、vbe6ext.tlh和excel.tlh。经由过程打开⽂件可知,该三个⽂件的定名空间分别是Office、VBIDE和Excel。导⼊了Excel的全部类型库后,就可以应⽤Excel中的所有类型了。
4、操纵Excel步调
操纵Excel的⾸要步调如下:
(1)创建⼀个Excel应⽤法度。
(2)获得Workbook的容器。
(3)打开⼀个Workbook或者创建⼀个Workbook。
(4)获得Workbook中的Worksheet的容器。
(5)打开⼀个Worksheet或者创建⼀个WorkSheet。
(6)经由过程Range对WorkSheet中的单位格进⾏读写操纵。
vba自学好学吗(7)保存Excel。
(8)开释资料。
5、批量处理惩罚Excel表格
VC经由过程OLE/COM操纵Excel,是经由过程过程间的组件技巧。是以,每次读写Excel中的单位格时,都要进⾏过程间的切换。当数据量⼤,若是⼀个单位格⼀个单位格的读取,⾸要的时候都花费在过程切换中。是以读取多个单位格,将可有效的进步法度的运⾏效⼒。
对多个单位格的读写操纵可以经由过程CRange中以下两个成员函数来完成。
VARIANT get_Value2();
void put_Value2(VARIANT& newValue);
此中,输⼊参数newValue只要输⼊⼀个⼆维数组,即可实现向Excel中⼀次写⼊多个单位格的值。
此中,VARIANT中实现⼆维数据的办法可参考
当然,在对CRange类进⾏操纵之前,要设置CRange类对应的单位格。
6、Excel表格的保存
(1)若是要保存打开的⼯作簿,应⽤CWorkbook类的Save函数就可以保存⼯作簿,原⽂件将被覆盖。
(2)若是是新创建的⼯作簿,或者是要另存为,可应⽤CWorkbook类的SaveAs函数。
SaveAs的参数⽃劲多。此中,第1个参数是设置要保存⽂件的路径;第2个参数是设置⽂件的格局,可在MSDN中查看列举类
型XlFileFormat来懂得Excel的⽂件格局。经过测试,在本⽂所⽤的测试景象中,Excel2003的⽂件格局是xlExcel8,Excel2007的⽂件格局是xlExcel4。
7、获取当前Excel的版本
可以经由过程CApplication的get_Version函数来获得Excel的版本,此中,Excel2007的主版本号是12,Excel2003的主版本号是11。
8、⽰例源代码
⾸要代码如下:
View Code m_ListCtrl.SetExtendedStyle(LVS_REPORT | LVS_EX_FULLROWSELECT); CApplication ExcelApp;
CWorkbooks books;
CWorkbook book;
CWorksheets sheets;
CWorksheet sheet;
CRange range;
LPDISPATCH lpDisp = NULL;
//创建Excel 办事器(启动Excel)
if(!ExcelApp.CreateDispatch(_T("Excel.Application"),NULL))
{
AfxMessageBox(_T("启动Excel办事器失败!"));
return -1;
}
CString strExcelVersion = _Version();
int iStart = 0;
strExcelVersion = strExcelVersion.Tokenize(_T("."), iStart);
if (_T("11") == strExcelVersion)
{
AfxMessageBox(_T("当前Excel的版本是2003。"));
}
else if (_T("12") == strExcelVersion)
{
AfxMessageBox(_T("当前Excel的版本是2007。"));
}
else
{
AfxMessageBox(_T("当前Excel的版本是其他版本。"));
}
ExcelApp.put_Visible(TRUE);
ExcelApp.put_UserControl(FALSE);
books.AttachDispatch(_Workbooks());
CString strBookPath = _T("C:\\tmp.xls");
try
{
lpDisp = books.Open(strBookPath,
vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,
vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,
vtMissing, vtMissing, vtMissing, vtMissing);
book.AttachDispatch(lpDisp);
}
catch(...)
{
lpDisp = books.Add(vtMissing);
book.AttachDispatch(lpDisp);
}
sheets.AttachDispatch(_Sheets());
CString strSheetName = _T("NewSheet");
try
{
lpDisp = _Item(_variant_t(strSheetName));
sheet.AttachDispatch(lpDisp);
}
catch(...)
{
lpDisp = sheets.Add(vtMissing, vtMissing, _variant_t((long)1), vtMissing); sheet.AttachDispatch(lpDisp);
sheet.put_Name(strSheetName);
}
system("pause");
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论