C++使用OLE高速读写EXCEL的源码
写了不少blog,也码了一点点文字,不知道为啥,被大家看的比较多几篇文章却总有那篇《C++读写EXCEL文件方式比较 》。
小小伤心一下,我blog里面写的很认真的文字还有几篇,这篇大概是最随意的文章。个人估计这是SEO的作用导致的。
另外,由于文中提到了可以加快OLE读取的EXCEL的速度,总有一些哥们找我要代码。
好吧,好吧,把代码放出来,因为我原来也是找人家的代码逐步改的。来而不往非礼也。
我的代码参考的地方是这儿,再次感谢原作者
http://blog.csdn.net/gyssoft/archive/2007/04/29/1592104.aspx
我根据自己的需要做了整理,干净了一点,而后根据发现的速度问题做了一些优化。
预加载的思路来自这个帖子
http://topic.csdn.net/t/20030626/21/1962211.html
其实思路很简单,不再一个CELL一个CELL的伛数据,而是一次把表格里面所有的数据读取出来处理。
.h文件的源码代码如下:
其中的头文件都是OLE的头文件。如何导出可以参考
http://blog.csdn.net/wyz365889/article/details/7599924
我自己这儿一直保存了一套别人生成的这几个文件,也可以用。大家可以找找有没有下载的,不过我不太确认跨版本是否可行。
还有既然是OLE,你一定要安装EXCEL的。
1 #pragma once 2 3 //OLE的头文件 4 #include <CRange.h> 5 #include <CWorkbook.h> 6 #include <CWorkbooks.h> 7 #include <CWorksheet.h> 8 #include <CWorksheets.h> 9 #include <CApplication.h> 10 11 /// 12 ///用于OLE的方式的EXCEL读写, 13 class IllusionExcelFile 14 { 15 16 public: 17 18 //构造函数和析构函数 19 IllusionExcelFile(); 20 virtual ~IllusionExcelFile(); 21 22 protected: 23 ///打开的EXCEL文件名称 24 CString open_excel_file_; 25 26 ///EXCEL BOOK集合,(多个文件时) 27 CWorkbooks excel_books_; 28 ///当前使用的BOOK,当前处理的文件 29 CWorkbook excel_work_book_; 30 ///EXCEL的sheets集合 31 CWorksheets excel_sheets_; 32 ///当前使用sheet 33 CWorksheet excel_work_sheet_; 34 ///当前的操作区域 35 CRange excel_current_range_; 36 37 38 ///是否已经预加载了某个sheet的数据 39 BOOL already_preload_; 40 ///Create the SAFEARRAY from the VARIANT ret. 41 COleSafeArray ole_safe_array_; 42 43 protected: 44 45 ///EXCEL的进程实例 46 static CApplication excel_application_; 47 public: 48 49 /// 50 void ShowInExcel(BOOL bShow); 51 52 ///检查一个CELL是否是字符串 53 BOOL IsCellString(long iRow, long iColumn); 54 ///检查一个CELL是否是数值 55 BOOL IsCellInt(long iRow, long iColumn); 56 57 ///得到一个CELL的String 58 CString GetCellString(long iRow, long iColumn); 59 ///得到整数 60 int GetCellInt(long iRow, long iColumn); 61 ///得到double的数据 62 double GetCellDouble(long iRow, long iColumn); 63 64 ///取得行的总数 65 int GetRowCount(); 66 ///取得列的总数 67 int GetColumnCount(); 68 69 ///使用某个shet,shit,shit 70 BOOL LoadSheet(long table_index,BOOL pre_load = FALSE); 71 ///通过名称使用某个sheet, 72 BOOL LoadSheet(const char* sheet,BOOL pre_load = FALSE); 73 ///通过序号取得某个Sheet的名称 74 CString GetSheetName(long table_index); 75 76 ///得到Sheet的总数 77 int GetSheetCount(); 78 79 ///打开文件 80 BOOL OpenExcelFile(const char * file_name); 81 ///关闭打开的Excel 文件,有时候打开EXCEL文件就要 82 void CloseExcelFile(BOOL if_save = FALSE); 83 //另存为一个EXCEL文件 84 void SaveasXSLFile(const CString &xls_file); 85 ///取得打开文件的名称 86 CString GetOpenFileName(); 87 ///取得打开sheet的名称 88 CString GetLoadSheetName(); 89 90 ///写入一个CELL一个int 91 void SetCellInt(long irow, long icolumn,int new_int); 92 ///写入一个CELL一个string 93 void SetCellString(long irow, long icolumn,CString new_string); 94 95 public: 96 ///初始化EXCEL OLE 97 static BOOL InitExcel(); 98 ///释放EXCEL的 OLE 99 static void ReleaseExcel(); 100 ///取得列的名称,比如27->AA 101 static char *GetColumnName(long iColumn); 102 103 protected: 104 105 //预先加载 106 void PreLoadSheet(); 107 };
CPP文件的与代码如下:
1 /****************************************************************************************** 2 Copyright : 2000-2004, Appache 2.0 3 FileName : illusion_excel_file.cpp 4 Author : Sail 5 Version : 6 Date Of Creation : 2009年4月3日 7 Description : 8 9 Others : 10 Function List : 11 1. ...... 12 Modification History: 13 1.Date : 14 Author : 15 Modification : 16 17 这个类是从网上下载的,我坐享其成,感谢原来的作者,我只试试是稍稍做了一下修正。 18 修正包括一些参数的使用不谨慎,bool 改为BOOL等,对于对象关系,我改了一部分,感觉原来的作者对于OO的思路部分不是很清楚。 19 对于这类东西OLE,我完全不了解,用别人封装的东西感觉还是放心了很多,C++,伟大的C++ 20 http://blog.csdn.net/gyssoft/archive/2007/04/29/1592104.aspx 21 22 OLE读写EXCEL都比较慢,所以应该尽量减少OLE的次数 23 对于读取,还有解决方法,请试用一下预加载的方式,这个方法一次加载所有的读取数据,如此速度就飞快了。 24 据说写数据是没有什么方法加快的 25 http://topic.csdn.net/t/20030626/21/1962211.html 26 27 增加了一些写入方式的代码,保证可以写入EXCEL数据区,但是对于保存,我发现如果调用CLOSE并且保存的方式, 28 速度非常慢,我不理解为什么。 29 所以我吧EXCEL打开了,让你进行后续管理, 30 31 32 ******************************************************************************************/ 33 34 35 36 37 //-----------------------excelfile.cpp---------------- 38 39 #include "StdAfx.h" 40 #include "illusion_excel_file.h" 41 42 43 44 COleVariant 45 covTrue((short)TRUE), 46 covFalse((short)FALSE), 47 covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); 48 49 // 50 CApplication IllusionExcelFile::excel_application_; 51 52 53 IllusionExcelFile::IllusionExcelFile(): 54 already_preload_(FALSE) 55 { 56 } 57 58 IllusionExcelFile::~IllusionExcelFile() 59 { 60 // 61 CloseExcelFile(); 62 } 63 64 65 //初始化EXCEL文件, 66 BOOL IllusionExcelFile::InitExcel() 67 { 68 69 //创建Excel 2000服务器(启动Excel) 70 if (!excel_application_.CreateDispatch("Excel.Application",NULL)) 71 { 72 AfxMessageBox("创建Excel服务失败,你可能没有安装EXCEL,请检查!"); 73 return FALSE; 74 } 75 76 excel_application_.put_DisplayAlerts(FALSE); 77 return TRUE; 78 } 79 80 // 81 void IllusionExcelFile::ReleaseExcel() 82 { 83 excel_application_.Quit(); 84 excel_application_.ReleaseDispatch(); 85 excel_application_=NULL; 86 } 87 88 //打开excel文件 89 BOOL IllusionExcelFile::OpenExcelFile(const char *file_name) 90 { 91 //先关闭 92 CloseExcelFile(); 93 94 //利用模板文件建立新文档 95 excel_books_.AttachDispatch(excel_application_.get_Workbooks(),true); 96 97 LPDISPATCH lpDis = NULL; 98 lpDis = excel_books_.Add(COleVariant(file_name)); 99 if (lpDis) 100 { 101 excel_work_book_.AttachDispatch(lpDis); 102 //得到Worksheets 103 excel_sheets_.AttachDispatch(excel_work_book_.get_Worksheets(),true); 104 105 //记录打开的文件名称 106 open_excel_file_ = file_name; 107 108 return TRUE; 109 } 110 111 return FALSE; 112 } 113 114 //关闭打开的Excel 文件,默认情况不保存文件 115 void IllusionExcelFile::CloseExcelFile(BOOL if_save) 116 { 117 //如果已经打开,关闭文件 118 if (open_excel_file_.IsEmpty() == FALSE) 119 { 120 //如果保存,交给用户控制,让用户自己存,如果自己SAVE,会出现莫名的等待 121 if (if_save) 122 { 123 ShowInExcel(TRUE); 124 } 125 else 126 { 127 // 128 excel_work_book_.Close(COleVariant(short(FALSE)),COleVariant(open_excel_file_),covOptional); 129 excel_books_.Close(); 130 } 131 132 //打开文件的名称清空 133 open_excel_file_.Empty(); 134 } 135 136 137 138 excel_sheets_.ReleaseDispatch(); 139 excel_work_sheet_.ReleaseDispatch(); 140 excel_current_range_.ReleaseDispatch(); 141 excel_work_book_.ReleaseDispatch(); 142 excel_books_.ReleaseDispatch(); 143 } 144 145 void IllusionExcelFile::SaveasXSLFile(const CString &xls_file) 146 { 147 excel_work_book_.SaveAs(COleVariant(xls_file), 148 covOptional, 149 covOptional, 150 covOptional, 151 covOptional, 152 covOptional, 153 0, 154 covOptional, 155 covOptional, 156 covOptional, 157 covOptional, 158 covOptional); 159 return; 160 } 161 162 163 int IllusionExcelFile::GetSheetCount() 164 { 165 return excel_sheets_.get_Count(); 166 } 167 168 169 CString IllusionExcelFile::GetSheetName(long table_index) 170 { 171 CWorksheet sheet; 172 sheet.AttachDispatch(excel_sheets_.get_Item(COleVariant((long)table_index)),true); 173 CString name = sheet.get_Name(); 174 sheet.ReleaseDispatch(); 175 return name; 176 } 177 178 //按照序号加载Sheet表格,可以提前加载所有的表格内部数据 179 BOOL IllusionExcelFile::LoadSheet(long table_index,BOOL pre_load) 180 { 181 LPDISPATCH lpDis = NULL; 182 excel_current_range_.ReleaseDispatch(); 183 excel_work_sheet_.ReleaseDispatch(); 184 lpDis = excel_sheets_.get_Item(COleVariant((long)table_index)); 185 if (lpDis) 186 { 187 excel_work_sheet_.AttachDispatch(lpDis,true); 188 excel_current_range_.AttachDispatch(excel_work_sheet_.get_Cells(), true); 189 } 190 else 191 { 192 return FALSE; 193 } 194 195 already_preload_ = FALSE; 196 //如果进行预先加载 197 if (pre_load) 198 { 199 PreLoadSheet(); 200 already_preload_ = TRUE; 201 } 202 203 return TRUE; 204 } 205 206 //按照名称加载Sheet表格,可以提前加载所有的表格内部数据 207 BOOL IllusionExcelFile::LoadSheet(const char* sheet,BOOL pre_load) 208 { 209 LPDISPATCH lpDis = NULL; 210 excel_current_range_.ReleaseDispatch(); 211 excel_work_sheet_.ReleaseDispatch(); 212 lpDis = excel_sheets_.get_Item(COleVariant(sheet)); 213 if (lpDis) 214 { 215 excel_work_sheet_.AttachDispatch(lpDis,true); 216 excel_current_range_.AttachDispatch(excel_work_sheet_.get_Cells(), true); 217 218 } 219 else 220 { 221 return FALSE; 222 } 223 // 224 already_preload_ = FALSE; 225 //如果进行预先加载 226 if (pre_load) 227 { 228 already_preload_ = TRUE; 229 PreLoadSheet(); 230 } 231 232 return TRUE; 233 } 234 235 //得到列的总数 236 int IllusionExcelFile::GetColumnCount() 237 { 238 CRange range; 239 CRange usedRange; 240 usedRange.AttachDispatch(excel_work_sheet_.get_UsedRange(), true); 241 range.AttachDispatch(usedRange.get_Columns(), true); 242 int count = range.get_Count(); 243 usedRange.ReleaseDispatch(); 244 range.ReleaseDispatch(); 245 return count; 246 } 247 248 //得到行的总数 249 int IllusionExcelFile::GetRowCount() 250 { 251 CRange range; 252 CRange usedRange; 253 usedRange.AttachDispatch(excel_work_sheet_.get_UsedRange(), true); 254 range.AttachDispatch(usedRange.get_Rows(), true); 255 int count = range.get_Count(); 256 usedRange.ReleaseDispatch(); 257 range.ReleaseDispatch(); 258 return count; 259 } 260 261 //检查一个CELL是否是字符串 262 BOOL IllusionExcelFile::IsCellString(long irow, long icolumn) 263 { 264 CRange range; 265 range.AttachDispatch(excel_current_range_.get_Item (COleVariant((long)irow),COleVariant((long)icolumn)).pdispVal, true); 266 COleVariant vResult =range.get_Value2(); 267 //VT_BSTR标示字符串 268 if(vResult.vt == VT_BSTR) 269 { 270 return TRUE; 271 } 272 return FALSE; 273 } 274 275 //检查一个CELL是否是数值 276 BOOL IllusionExcelFile::IsCellInt(long irow, long icolumn) 277 { 278 CRange range; 279 range.AttachDispatch(excel_current_range_.get_Item (COleVariant((long)irow),COleVariant((long)icolumn)).pdispVal, true); 280 COleVariant vResult =range.get_Value2(); 281 //好像一般都是VT_R8 282 if(vResult.vt == VT_INT || vResult.vt == VT_R8) 283 { 284 return TRUE; 285 } 286 return FALSE; 287 } 288 289 // 290 CString IllusionExcelFile::GetCellString(long irow, long icolumn) 291 { 292 293 COleVariant vResult ; 294 CString str; 295 //字符串 296 if (already_preload_ == FALSE) 297 { 298 CRange range; 299 range.AttachDispatch(excel_current_range_.get_Item (COleVariant((long)irow),COleVariant((long)icolumn)).pdispVal, true); 300 vResult =range.get_Value2(); 301 range.ReleaseDispatch(); 302 } 303 //如果数据依据预先加载了 304 else 305 { 306 long read_address[2]; 307 VARIANT val; 308 read_address[0] = irow; 309 read_address[1] = icolumn; 310 ole_safe_array_.GetElement(read_address, &val); 311 vResult = val; 312 } 313 314 if(vResult.vt == VT_BSTR) 315 { 316 str=vResult.bstrVal; 317 } 318 //整数 319 else if (vResult.vt==VT_INT) 320 { 321 str.Format("%d",vResult.pintVal); 322 } 323 //8字节的数字 324 else if (vResult.vt==VT_R8) 325 { 326 str.Format("%0.0f",vResult.dblVal); 327 } 328 //时间格式 329 else if(vResult.vt==VT_DATE) 330 { 331 SYSTEMTIME st; 332 VariantTimeToSystemTime(vResult.date, &st); 333 CTime tm(st); 334 str=tm.Format("%Y-%m-%d"); 335 336 } 337 //单元格空的 338 else if(vResult.vt==VT_EMPTY) 339 { 340 str=""; 341 } 342 343 return str; 344 } 345 346 double IllusionExcelFile::GetCellDouble(long irow, long icolumn) 347 { 348 double rtn_value = 0; 349 COleVariant vresult; 350 //字符串 351 if (already_preload_ == FALSE) 352 { 353 CRange range; 354 range.AttachDispatch(excel_current_range_.get_Item (COleVariant((long)irow),COleVariant((long)icolumn)).pdispVal, true); 355 vresult =range.get_Value2(); 356 range.ReleaseDispatch(); 357 } 358 //如果数据依据预先加载了 359 else 360 { 361 long read_address[2]; 362 VARIANT val; 363 read_address[0] = irow; 364 read_address[1] = icolumn; 365 ole_safe_array_.GetElement(read_address, &val); 366 vresult = val; 367 } 368 369 if (vresult.vt==VT_R8) 370 { 371 rtn_value = vresult.dblVal; 372 } 373 374 return rtn_value; 375 } 376 377 //VT_R8 378 int IllusionExcelFile::GetCellInt(long irow, long icolumn) 379 { 380 int num; 381 COleVariant vresult; 382 383 if (already_preload_ == FALSE) 384 { 385 CRange range; 386 range.AttachDispatch(excel_current_range_.get_Item (COleVariant((long)irow),COleVariant((long)icolumn)).pdispVal, true); 387 vresult = range.get_Value2(); 388 range.ReleaseDispatch(); 389 } 390 else 391 { 392 long read_address[2]; 393 VARIANT val; 394 read_address[0] = irow; 395 read_address[1] = icolumn; 396 ole_safe_array_.GetElement(read_address, &val); 397 vresult = val; 398 } 399 // 400 num = static_cast<int>(vresult.dblVal); 401 402 return num; 403 } 404 405 void IllusionExcelFile::SetCellString(long irow, long icolumn,CString new_string) 406 { 407 COleVariant new_value(new_string); 408 CRange start_range = excel_work_sheet_.get_Range(COleVariant("A1"),covOptional); 409 CRange write_range = start_range.get_Offset(COleVariant((long)irow -1),COleVariant((long)icolumn -1) ); 410 write_range.put_Value2(new_value); 411 start_range.ReleaseDispatch(); 412 write_range.ReleaseDispatch(); 413 414 } 415 416 void IllusionExcelFile::SetCellInt(long irow, long icolumn,int new_int) 417 { 418 COleVariant new_value((long)new_int); 419 420 CRange start_range = excel_work_sheet_.get_Range(COleVariant("A1"),covOptional); 421 CRange write_range = start_range.get_Offset(COleVariant((long)irow -1),COleVariant((long)icolumn -1) ); 422 write_range.put_Value2(new_value); 423 start_range.ReleaseDispatch(); 424 write_range.ReleaseDispatch(); 425 } 426 427 428 // 429 void IllusionExcelFile::ShowInExcel(BOOL bShow) 430 { 431 excel_application_.put_Visible(bShow); 432 excel_application_.put_UserControl(bShow); 433 } 434 435 //返回打开的EXCEL文件名称 436 CString IllusionExcelFile::GetOpenFileName() 437 { 438 return open_excel_file_; 439 } 440 441 //取得打开sheet的名称 442 CString IllusionExcelFile::GetLoadSheetName() 443 { 444 return excel_work_sheet_.get_Name(); 445 } 446 447 //取得列的名称,比如27->AA 448 char *IllusionExcelFile::GetColumnName(long icolumn) 449 { 450 static char column_name[64]; 451 size_t str_len = 0; 452 453 while(icolumn > 0) 454 { 455 int num_data = icolumn % 26; 456 icolumn /= 26; 457 if (num_data == 0) 458 { 459 num_data = 26; 460 icolumn--; 461 } 462 column_name[str_len] = (char)((num_data-1) + 'A' ); 463 str_len ++; 464 } 465 column_name[str_len] = '\0'; 466 //反转 467 _strrev(column_name); 468 469 return column_name; 470 } 471 472 //预先加载 473 void IllusionExcelFile::PreLoadSheet() 474 { 475 476 CRange used_range; 477 478 used_range = excel_work_sheet_.get_UsedRange(); 479 480 481 VARIANT ret_ary = used_range.get_Value2(); 482 if (!(ret_ary.vt & VT_ARRAY)) 483 { 484 return; 485 } 486 // 487 ole_safe_array_.Clear(); 488 ole_safe_array_.Attach(ret_ary); 489 }
【本文作者是雁渡寒潭,本着自由的精神,你可以在无盈利的情况完整转载此文档,转载时请附上BLOG链接:http://www.cnblogs.com/fullsail/ 或者http://blog.csdn.net/fullsail,否则每字一元,每图一百不讲价。对Baidu文库。360doc加价一倍】