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加價一倍】
發佈了28 篇原創文章 · 獲贊 7 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章