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加价一倍】
 
 
原文地址:https://www.cnblogs.com/fullsail/p/2837952.html