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加價一倍】
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM