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的。
#pragma once//OLE的頭文件 #include <CRange.h> #include <CWorkbook.h> #include <CWorkbooks.h> #include <CWorksheet.h> #include <CWorksheets.h> #include <CApplication.h>/// ///用于OLE的方式的EXCEL讀寫, class IllusionExcelFile {public://構造函數和析構函數IllusionExcelFile();virtual ~IllusionExcelFile();protected:///打開的EXCEL文件名稱CString open_excel_file_;///EXCEL BOOK集合,(多個文件時)CWorkbooks excel_books_; ///當前使用的BOOK,當前處理的文件CWorkbook excel_work_book_; ///EXCEL的sheets集合CWorksheets excel_sheets_; ///當前使用sheetCWorksheet excel_work_sheet_; ///當前的操作區域CRange excel_current_range_; ///是否已經預加載了某個sheet的數據BOOL already_preload_;///Create the SAFEARRAY from the VARIANT ret.COleSafeArray ole_safe_array_;protected:///EXCEL的進程實例static CApplication excel_application_; public:///void ShowInExcel(BOOL bShow);///檢查一個CELL是否是字符串BOOL IsCellString(long iRow, long iColumn);///檢查一個CELL是否是數值BOOL IsCellInt(long iRow, long iColumn);///得到一個CELL的StringCString GetCellString(long iRow, long iColumn);///得到整數int GetCellInt(long iRow, long iColumn);///得到double的數據double GetCellDouble(long iRow, long iColumn);///取得行的總數int GetRowCount();///取得列的總數int GetColumnCount();///使用某個shet,shit,shitBOOL LoadSheet(long table_index,BOOL pre_load = FALSE);///通過名稱使用某個sheet,BOOL LoadSheet(const char* sheet,BOOL pre_load = FALSE);///通過序號取得某個Sheet的名稱CString GetSheetName(long table_index);///得到Sheet的總數int GetSheetCount();///打開文件BOOL OpenExcelFile(const char * file_name);///關閉打開的Excel 文件,有時候打開EXCEL文件就要void CloseExcelFile(BOOL if_save = FALSE);//另存為一個EXCEL文件void SaveasXSLFile(const CString &xls_file);///取得打開文件的名稱CString GetOpenFileName();///取得打開sheet的名稱CString GetLoadSheetName();///寫入一個CELL一個intvoid SetCellInt(long irow, long icolumn,int new_int);///寫入一個CELL一個stringvoid SetCellString(long irow, long icolumn,CString new_string);public:///初始化EXCEL OLEstatic BOOL InitExcel();///釋放EXCEL的 OLEstatic void ReleaseExcel();///取得列的名稱,比如27->AAstatic char *GetColumnName(long iColumn);protected://預先加載void PreLoadSheet(); };
CPP文件的與代碼如下:
/****************************************************************************************** Copyright : 2000-2004, Appache 2.0 FileName : illusion_excel_file.cpp Author : Sail Version : Date Of Creation : 2009年4月3日 Description : Others : Function List : 1. ......Modification History:1.Date : Author : Modification :這個類是從網上下載的,我坐享其成,感謝原來的作者,我只試試是稍稍做了一下修正。修正包括一些參數的使用不謹慎,bool 改為BOOL等,對于對象關系,我改了一部分,感覺原來的作者對于OO的思路部分不是很清楚。對于這類東西OLE,我完全不了解,用別人封裝的東西感覺還是放心了很多,C++,偉大的C++http://blog.csdn.net/gyssoft/archive/2007/04/29/1592104.aspxOLE讀寫EXCEL都比較慢,所以應該盡量減少OLE的次數對于讀取,還有解決方法,請試用一下預加載的方式,這個方法一次加載所有的讀取數據,如此速度就飛快了。據說寫數據是沒有什么方法加快的http://topic.csdn.net/t/20030626/21/1962211.html增加了一些寫入方式的代碼,保證可以寫入EXCEL數據區,但是對于保存,我發現如果調用CLOSE并且保存的方式,速度非常慢,我不理解為什么。所以我吧EXCEL打開了,讓你進行后續管理,******************************************************************************************///-----------------------excelfile.cpp----------------#include "StdAfx.h" #include "illusion_excel_file.h"COleVariant covTrue((short)TRUE), covFalse((short)FALSE), covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); // CApplication IllusionExcelFile::excel_application_;IllusionExcelFile::IllusionExcelFile():already_preload_(FALSE) { }IllusionExcelFile::~IllusionExcelFile() {//CloseExcelFile(); }//初始化EXCEL文件, BOOL IllusionExcelFile::InitExcel() {//創建Excel 2000服務器(啟動Excel) if (!excel_application_.CreateDispatch("Excel.Application",NULL)) { AfxMessageBox("創建Excel服務失敗,你可能沒有安裝EXCEL,請檢查!"); return FALSE;}excel_application_.put_DisplayAlerts(FALSE); return TRUE; }// void IllusionExcelFile::ReleaseExcel() {excel_application_.Quit();excel_application_.ReleaseDispatch();excel_application_=NULL; }//打開excel文件 BOOL IllusionExcelFile::OpenExcelFile(const char *file_name) {//先關閉CloseExcelFile();//利用模板文件建立新文檔 excel_books_.AttachDispatch(excel_application_.get_Workbooks(),true); LPDISPATCH lpDis = NULL;lpDis = excel_books_.Add(COleVariant(file_name)); if (lpDis){excel_work_book_.AttachDispatch(lpDis); //得到Worksheets excel_sheets_.AttachDispatch(excel_work_book_.get_Worksheets(),true); //記錄打開的文件名稱open_excel_file_ = file_name;return TRUE;}return FALSE; }//關閉打開的Excel 文件,默認情況不保存文件 void IllusionExcelFile::CloseExcelFile(BOOL if_save) {//如果已經打開,關閉文件if (open_excel_file_.IsEmpty() == FALSE){//如果保存,交給用戶控制,讓用戶自己存,如果自己SAVE,會出現莫名的等待if (if_save){ShowInExcel(TRUE);}else{//excel_work_book_.Close(COleVariant(short(FALSE)),COleVariant(open_excel_file_),covOptional);excel_books_.Close();}//打開文件的名稱清空open_excel_file_.Empty();}excel_sheets_.ReleaseDispatch();excel_work_sheet_.ReleaseDispatch();excel_current_range_.ReleaseDispatch();excel_work_book_.ReleaseDispatch();excel_books_.ReleaseDispatch(); }void IllusionExcelFile::SaveasXSLFile(const CString &xls_file) {excel_work_book_.SaveAs(COleVariant(xls_file),covOptional,covOptional,covOptional,covOptional,covOptional,0,covOptional,covOptional,covOptional,covOptional,covOptional);return; }int IllusionExcelFile::GetSheetCount() {return excel_sheets_.get_Count(); }CString IllusionExcelFile::GetSheetName(long table_index) {CWorksheet sheet;sheet.AttachDispatch(excel_sheets_.get_Item(COleVariant((long)table_index)),true);CString name = sheet.get_Name();sheet.ReleaseDispatch();return name; }//按照序號加載Sheet表格,可以提前加載所有的表格內部數據 BOOL IllusionExcelFile::LoadSheet(long table_index,BOOL pre_load) {LPDISPATCH lpDis = NULL;excel_current_range_.ReleaseDispatch();excel_work_sheet_.ReleaseDispatch();lpDis = excel_sheets_.get_Item(COleVariant((long)table_index));if (lpDis){excel_work_sheet_.AttachDispatch(lpDis,true);excel_current_range_.AttachDispatch(excel_work_sheet_.get_Cells(), true);}else{return FALSE;}already_preload_ = FALSE;//如果進行預先加載if (pre_load){PreLoadSheet();already_preload_ = TRUE;}return TRUE; }//按照名稱加載Sheet表格,可以提前加載所有的表格內部數據 BOOL IllusionExcelFile::LoadSheet(const char* sheet,BOOL pre_load) {LPDISPATCH lpDis = NULL;excel_current_range_.ReleaseDispatch();excel_work_sheet_.ReleaseDispatch();lpDis = excel_sheets_.get_Item(COleVariant(sheet));if (lpDis){excel_work_sheet_.AttachDispatch(lpDis,true);excel_current_range_.AttachDispatch(excel_work_sheet_.get_Cells(), true);}else{return FALSE;}//already_preload_ = FALSE;//如果進行預先加載if (pre_load){already_preload_ = TRUE;PreLoadSheet();}return TRUE; }//得到列的總數 int IllusionExcelFile::GetColumnCount() {CRange range;CRange usedRange;usedRange.AttachDispatch(excel_work_sheet_.get_UsedRange(), true);range.AttachDispatch(usedRange.get_Columns(), true);int count = range.get_Count();usedRange.ReleaseDispatch();range.ReleaseDispatch();return count; }//得到行的總數 int IllusionExcelFile::GetRowCount() {CRange range;CRange usedRange;usedRange.AttachDispatch(excel_work_sheet_.get_UsedRange(), true);range.AttachDispatch(usedRange.get_Rows(), true);int count = range.get_Count();usedRange.ReleaseDispatch();range.ReleaseDispatch();return count; }//檢查一個CELL是否是字符串 BOOL IllusionExcelFile::IsCellString(long irow, long icolumn) {CRange range;range.AttachDispatch(excel_current_range_.get_Item (COleVariant((long)irow),COleVariant((long)icolumn)).pdispVal, true);COleVariant vResult =range.get_Value2();//VT_BSTR標示字符串if(vResult.vt == VT_BSTR) {return TRUE;}return FALSE; }//檢查一個CELL是否是數值 BOOL IllusionExcelFile::IsCellInt(long irow, long icolumn) {CRange range;range.AttachDispatch(excel_current_range_.get_Item (COleVariant((long)irow),COleVariant((long)icolumn)).pdispVal, true);COleVariant vResult =range.get_Value2();//好像一般都是VT_R8if(vResult.vt == VT_INT || vResult.vt == VT_R8) {return TRUE;}return FALSE; }// CString IllusionExcelFile::GetCellString(long irow, long icolumn) {COleVariant vResult ;CString str;//字符串if (already_preload_ == FALSE){CRange range;range.AttachDispatch(excel_current_range_.get_Item (COleVariant((long)irow),COleVariant((long)icolumn)).pdispVal, true);vResult =range.get_Value2();range.ReleaseDispatch();}//如果數據依據預先加載了else{long read_address[2];VARIANT val;read_address[0] = irow;read_address[1] = icolumn;ole_safe_array_.GetElement(read_address, &val);vResult = val;}if(vResult.vt == VT_BSTR){str=vResult.bstrVal;}//整數else if (vResult.vt==VT_INT){str.Format("%d",vResult.pintVal);}//8字節的數字 else if (vResult.vt==VT_R8) {str.Format("%0.0f",vResult.dblVal);}//時間格式else if(vResult.vt==VT_DATE) {SYSTEMTIME st;VariantTimeToSystemTime(vResult.date, &st);CTime tm(st); str=tm.Format("%Y-%m-%d");}//單元格空的else if(vResult.vt==VT_EMPTY) {str="";} return str; }double IllusionExcelFile::GetCellDouble(long irow, long icolumn) {double rtn_value = 0;COleVariant vresult;//字符串if (already_preload_ == FALSE){CRange range;range.AttachDispatch(excel_current_range_.get_Item (COleVariant((long)irow),COleVariant((long)icolumn)).pdispVal, true);vresult =range.get_Value2();range.ReleaseDispatch();}//如果數據依據預先加載了else{long read_address[2];VARIANT val;read_address[0] = irow;read_address[1] = icolumn;ole_safe_array_.GetElement(read_address, &val);vresult = val;}if (vresult.vt==VT_R8) {rtn_value = vresult.dblVal;}return rtn_value; }//VT_R8 int IllusionExcelFile::GetCellInt(long irow, long icolumn) {int num;COleVariant vresult;if (already_preload_ == FALSE){CRange range;range.AttachDispatch(excel_current_range_.get_Item (COleVariant((long)irow),COleVariant((long)icolumn)).pdispVal, true);vresult = range.get_Value2();range.ReleaseDispatch();}else{long read_address[2];VARIANT val;read_address[0] = irow;read_address[1] = icolumn;ole_safe_array_.GetElement(read_address, &val);vresult = val;}//num = static_cast<int>(vresult.dblVal);return num; }void IllusionExcelFile::SetCellString(long irow, long icolumn,CString new_string) {COleVariant new_value(new_string);CRange start_range = excel_work_sheet_.get_Range(COleVariant("A1"),covOptional);CRange write_range = start_range.get_Offset(COleVariant((long)irow -1),COleVariant((long)icolumn -1) );write_range.put_Value2(new_value);start_range.ReleaseDispatch();write_range.ReleaseDispatch();}void IllusionExcelFile::SetCellInt(long irow, long icolumn,int new_int) {COleVariant new_value((long)new_int);CRange start_range = excel_work_sheet_.get_Range(COleVariant("A1"),covOptional);CRange write_range = start_range.get_Offset(COleVariant((long)irow -1),COleVariant((long)icolumn -1) );write_range.put_Value2(new_value);start_range.ReleaseDispatch();write_range.ReleaseDispatch(); }// void IllusionExcelFile::ShowInExcel(BOOL bShow) {excel_application_.put_Visible(bShow);excel_application_.put_UserControl(bShow); }//返回打開的EXCEL文件名稱 CString IllusionExcelFile::GetOpenFileName() {return open_excel_file_; }//取得打開sheet的名稱 CString IllusionExcelFile::GetLoadSheetName() {return excel_work_sheet_.get_Name(); }//取得列的名稱,比如27->AA char *IllusionExcelFile::GetColumnName(long icolumn) { static char column_name[64];size_t str_len = 0;while(icolumn > 0){int num_data = icolumn % 26;icolumn /= 26;if (num_data == 0){num_data = 26;icolumn--;}column_name[str_len] = (char)((num_data-1) + 'A' );str_len ++;}column_name[str_len] = '\0';//反轉_strrev(column_name);return column_name; }//預先加載 void IllusionExcelFile::PreLoadSheet() {CRange used_range;used_range = excel_work_sheet_.get_UsedRange(); VARIANT ret_ary = used_range.get_Value2();if (!(ret_ary.vt & VT_ARRAY)){return;}//ole_safe_array_.Clear();ole_safe_array_.Attach(ret_ary); } 【本文作者是雁渡寒潭,本著自由的精神,你可以在無盈利的情況完整轉載此文檔,轉載時請附上BLOG鏈接:http://www.cnblogs.com/fullsail/ 或者http://blog.csdn.net/fullsail,否則每字一元,每圖一百不講價。對Baidu文庫。360doc加價一倍】
總結
以上是生活随笔為你收集整理的C++使用OLE高速读写EXCEL的源码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Epicor 客制化 - 常用对象
- 下一篇: Go Anywhere Chair