zoukankan      html  css  js  c++  java
  • 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加价一倍】
     
     
  • 相关阅读:
    工作流学习——Activiti流程变量五步曲
    Rational Performance Tester(RPTv8.6) 在launch Schedule 时一直卡在 29%
    19、Cocos2dx 3.0游戏开发找小三之Action:流动的水没有形状,漂流的风找不到踪迹、、、
    【设计模式】责任链模式
    redis源代码分析(5)——aof
    Servlet基础梳理(四)
    SQL-W3School-高级:SQL 数据类型
    SQL-W3School-高级:SQL NULL 函数
    SQL-W3School-高级:SQL NULL 值
    SQL-W3School-高级:SQL Date 函数
  • 原文地址:https://www.cnblogs.com/fullsail/p/2837952.html
Copyright © 2011-2022 走看看