c++ 對 EXCEL 讀寫的封裝
阿新 • • 發佈:2019-02-04
ExcelOp.h
#pragma once //http://b217dgy.blog.51cto.com/5704306/1215234 //http://www.blogjava.net/jinheking/archive/2005/07/19/5150.html 合併單元格 //http://blog.csdn.net/qinghezhen/article/details/9906023 //http://blog.csdn.net/gyssoft/article/details/1592104 //http://read.pudn.com/downloads100/doc/fileformat/411493/C++/ComTypeLibfor7/comexcel/excel10/comexcel.cpp__.htm //http://www.cnblogs.com/fullsail/archive/2012/12/28/2837952.html 使用OLE高速讀寫EXCEL的原始碼 //http://blog.csdn.net/handsing/article/details/5461070 //http://www.cnblogs.com/xianyunhe/archive/2011/09/13/2174703.html //http://www.update8.com/Program/C++/27229.html //http://bbs.csdn.net/topics/390091827 #include "stdafx.h" //OLE的標頭檔案 #include "CRange.h" #include "CWorkbook.h" #include "CWorkbooks.h" #include "CWorksheet.h" #include "CWorksheets.h" #include "CApplication.h" class CExcelOp { public: CExcelOp(void); ~CExcelOp(void); public: void ShowInExcel(BOOL bShow); ///檢查一個CELL是否是字串 //BOOL IsCellString(long iRow, long iColumn); ///檢查一個CELL是否是數值 //BOOL IsCellInt(long iRow, long iColumn); void SetCell(long irow, long icolumn,CString new_string); ///得到一個CELL的String CString GetCell(long iRow, long iColumn); CString GetCellByName(CString rowName,CString colName); ///得到整數 //int GetCellInt(long iRow, long iColumn); ///得到double的資料 //double GetCellDouble(long iRow, long iColumn); ///取得行的總數 int GetRowCount(); ///取得列的總數 int GetColumnCount(); ///使用某個shet,shit,shit BOOL LoadSheet(long table_index,BOOL pre_load = FALSE); ///通過名稱使用某個sheet, BOOL LoadSheet(const TCHAR* sheet,BOOL pre_load = FALSE); ///通過序號取得某個Sheet的名稱 CString GetSheetName(long table_index); ///得到Sheet的總數 int GetSheetCount(); ///開啟檔案 BOOL OpenExcelFile(const TCHAR * file_name); ///關閉開啟的Excel 檔案,有時候開啟EXCEL檔案就要 void CloseExcelFile(BOOL if_save = FALSE); //另存為一個EXCEL檔案 void SaveasXSLFile(const CString &xls_file); ///取得開啟檔案的名稱 CString GetOpenFileName(); ///取得開啟sheet的名稱 CString GetLoadSheetName(); ///寫入一個CELL一個int //void SetCellInt(long irow, long icolumn,int new_int); ///寫入一個CELL一個string //void SetCellString(long irow, long icolumn,CString new_string); public: ///初始化EXCEL OLE static BOOL InitExcel(); ///釋放EXCEL的 OLE static void ReleaseExcel(); ///取得列的名稱,比如27->AA static char *GetColumnName(long iColumn); protected: //預先載入 void PreLoadSheet(); public: ///開啟的EXCEL檔名稱 CString open_excel_file_; CWorkbooks m_Books; CWorkbook m_Book; CWorksheets m_sheets; CWorksheet m_sheet; CRange m_Rge; static CApplication m_app; ///是否已經預載入了某個sheet的資料 BOOL already_preload_; ///Create the SAFEARRAY from the VARIANT ret. COleSafeArray ole_safe_array_; LPDISPATCH m_lpDisp; };
ExcelOp.cpp
#include "StdAfx.h" #include "ExcelOp.h" #ifdef _DEBUG #define new DEBUG_NEW #endif CExcelOp::CExcelOp(void):already_preload_(FALSE) { } CExcelOp::~CExcelOp(void) { } COleVariant covTrue((short)TRUE), covFalse((short)FALSE), covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); CApplication CExcelOp::m_app; //初始化EXCEL檔案, BOOL CExcelOp::InitExcel() { BOOL bRtn =FALSE ; TCHAR* ptchsExcel[]={ _T("Excel.Application") //建立Excel 2000伺服器(啟動Excel) ,_T("Excel.Application.8")//Excel 97 ,_T("Excel.Application.9")//Excel 2000 ,_T("Excel.Application.10")//Excel xp ,_T("Excel.Application.11")//Excel 2003 ,_T("Excel.Application.12")//Excel 2007 ,_T("Excel.Application.14")//Excel 2010 }; CLSID clsid; HRESULT hr = S_FALSE; for (int i= sizeof(ptchsExcel)/sizeof(*ptchsExcel)-1;i>=0;i--) { #if 0 if (m_app.CreateDispatch(ptchsExcel[i],NULL)) { break; } 等同於下面的操作 #else hr = CLSIDFromProgID(ptchsExcel[i], &clsid); if(SUCCEEDED(hr)) { hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&m_app); if(SUCCEEDED(hr)) { bRtn = TRUE; } break; } #endif } if (!bRtn) { AfxMessageBox(_T("建立Excel服務失敗,你可能沒有安裝EXCEL,請檢查!")); return bRtn; } m_app.put_DisplayAlerts(FALSE); return bRtn; } // void CExcelOp::ReleaseExcel() { m_app.Quit(); m_app.ReleaseDispatch(); m_app=NULL; } //關閉開啟的Excel 檔案,預設情況不儲存檔案 void CExcelOp::CloseExcelFile(BOOL if_save) { //如果已經開啟,關閉檔案 if (open_excel_file_.IsEmpty() == FALSE) { //如果儲存,交給使用者控制,讓使用者自己存,如果自己SAVE,會出現莫名的等待 if (if_save) { ShowInExcel(TRUE); } else { m_Book.Close(COleVariant(short(FALSE)),COleVariant(open_excel_file_),covOptional); m_Books.Close(); } //開啟檔案的名稱清空 open_excel_file_.Empty(); } m_sheets.ReleaseDispatch(); m_sheet.ReleaseDispatch(); m_Rge.ReleaseDispatch(); m_Book.ReleaseDispatch(); m_Books.ReleaseDispatch(); } //開啟excel檔案 BOOL CExcelOp::OpenExcelFile(const TCHAR *file_name) { //先關閉 CloseExcelFile(); //m_Books.AttachDispatch(m_app.get_Workbooks(),1); //COleVariant varPath(file_name); //m_Book.AttachDispatch(m_Books.Add(varPath)); //利用模板檔案建立新文件 m_Books.AttachDispatch(m_app.get_Workbooks(),true); //LPDISPATCH lpDis = NULL; m_lpDisp = m_Books.Add(COleVariant(file_name)); if (m_lpDisp) { m_Book.AttachDispatch(m_lpDisp); //得到Worksheets m_sheets.AttachDispatch(m_Book.get_Worksheets(),true); //記錄開啟的檔名稱 open_excel_file_ = file_name; return TRUE; } return TRUE; } // void CExcelOp::ShowInExcel(BOOL bShow) { m_app.put_Visible(bShow); m_app.put_UserControl(bShow); } void CExcelOp::SaveasXSLFile(const CString &xls_file) { m_Book.SaveAs(COleVariant(xls_file), covOptional, covOptional, covOptional, covOptional, covOptional, 0, covOptional, covOptional, covOptional, covOptional, covOptional); return; } int CExcelOp::GetSheetCount() { return m_sheets.get_Count(); } CString CExcelOp::GetSheetName(long table_index) { CWorksheet sheet; sheet.AttachDispatch(m_sheets.get_Item(COleVariant((long)table_index)),true); CString name = sheet.get_Name(); sheet.ReleaseDispatch(); return name; } //按照序號載入Sheet表格,可以提前載入所有的表格內部資料 BOOL CExcelOp::LoadSheet(long table_index,BOOL pre_load) { LPDISPATCH lpDis = NULL; m_Rge.ReleaseDispatch(); m_sheet.ReleaseDispatch(); lpDis = m_sheets.get_Item(COleVariant((long)table_index)); if (lpDis) { m_sheet.AttachDispatch(lpDis,true); m_Rge.AttachDispatch(m_sheet.get_Cells(), true); } else { return FALSE; } already_preload_ = FALSE; //如果進行預先載入 if (pre_load) { PreLoadSheet(); already_preload_ = TRUE; } return TRUE; } //按照名稱載入Sheet表格,可以提前載入所有的表格內部資料 BOOL CExcelOp::LoadSheet(const TCHAR* sheet,BOOL pre_load) { LPDISPATCH lpDis = NULL; m_Rge.ReleaseDispatch(); m_sheet.ReleaseDispatch(); lpDis = m_sheets.get_Item(COleVariant(sheet)); if (lpDis) { m_sheet.AttachDispatch(lpDis,true); m_Rge.AttachDispatch(m_sheet.get_Cells(), true); } else { return FALSE; } // already_preload_ = FALSE; //如果進行預先載入 if (pre_load) { already_preload_ = TRUE; PreLoadSheet(); } return TRUE; } //得到列的總數 int CExcelOp::GetColumnCount() { CRange range; CRange usedRange; usedRange.AttachDispatch(m_sheet.get_UsedRange(), true); range.AttachDispatch(usedRange.get_Columns(), true); int count = range.get_Count(); usedRange.ReleaseDispatch(); range.ReleaseDispatch(); return count; } //得到行的總數 int CExcelOp::GetRowCount() { CRange range; CRange usedRange; usedRange.AttachDispatch(m_sheet.get_UsedRange(), true); range.AttachDispatch(usedRange.get_Rows(), true); int count = range.get_Count(); usedRange.ReleaseDispatch(); range.ReleaseDispatch(); return count; } //返回開啟的EXCEL檔名稱 CString CExcelOp::GetOpenFileName() { return open_excel_file_; } //取得開啟sheet的名稱 CString CExcelOp::GetLoadSheetName() { return m_sheet.get_Name(); } //取得列的名稱,比如27->AA char *CExcelOp::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 CExcelOp::PreLoadSheet() { CRange used_range; used_range = m_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); } void CExcelOp::SetCell(long irow, long icolumn,CString new_string) { COleVariant new_value(new_string); CRange start_range = m_sheet.get_Range(COleVariant(_T("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(); } CString CExcelOp::GetCell(long iRow, long iColumn) { COleVariant vResult ; //字串 if (already_preload_ == FALSE) { m_Rge.AttachDispatch(m_Rge.get_Item (COleVariant((long)iRow),COleVariant((long)iColumn)).pdispVal, true); vResult =m_Rge.get_Value2(); } //如果資料依據預先載入了 else { long read_address[2]; VARIANT val; read_address[0] = iRow; read_address[1] = iColumn; ole_safe_array_.GetElement(read_address, &val); vResult = val; } CString str; if(vResult.vt == VT_BSTR) //字串 { str=vResult.bstrVal; } else if (vResult.vt==VT_INT) { str.Format(_T("%d"),vResult.pintVal); } else if (vResult.vt==VT_R8) //8位元組的數字 { str.Format(_T("%0.0f"),vResult.dblVal); } else if(vResult.vt==VT_DATE) //時間格式 { SYSTEMTIME st; VariantTimeToSystemTime(vResult.date, &st); CTime tm(st); str=tm.Format(_T("%Y-%m-%d")); } else if(vResult.vt==VT_EMPTY) //單元格空的 { str=_T(""); } m_Rge.ReleaseDispatch(); return str; } CString CExcelOp::GetCellByName(CString rowName,CString colName) { COleVariant value; CString strValue; long row=0,col=0; long re_row=0,re_col=0; m_Rge.AttachDispatch(m_sheet.get_Cells(),TRUE); for (row=1,col=1;col<m_Rge.get_Column();col++) { value=m_Rge.get_Item(_variant_t(row),_variant_t(col)); //返回的型別是VT_DISPATCH 這是一個指標 m_Rge.AttachDispatch(value.pdispVal,TRUE); VARIANT value2=m_Rge.get_Text(); CString strValue=value2.bstrVal; if (strValue==colName) break; } re_col=col; for (row=1,row=1;row<m_Rge.get_Row();row++) { value=m_Rge.get_Item(_variant_t(row),_variant_t(col)); //返回的型別是VT_DISPATCH 這是一個指標 m_Rge.AttachDispatch(value.pdispVal,TRUE); VARIANT value2=m_Rge.get_Text(); CString strValue=value2.bstrVal; if (strValue==rowName) break; } re_row=row; return GetCell(re_row,re_col); }
用例 :
網上能直接拿來用的程式碼不多. 這部分程式碼取自網路各個地方,我都一一註明.m_excel = new CExcelOp(); CExcelOp::InitExcel(); nsYLX::CUtil::GetModulePath(IN OUT m_ptchCurrPath,IN MAX_PATH); TCHAR tchsExcelPath[MAX_PATH]; //獲得上一級目錄 nsYLX::CUtil::GetParentPath(IN m_ptchCurrPath, OUT tchsExcelPath, IN MAX_PATH, 1); TCHAR tchs[MAX_PATH]; nsYLX::CUtil::GenericAbsFullPath(IN tchsExcelPath,IN _T("files/2013淘寶雙11活動商品內部清單(史上陣容強大15萬商品價格提前曝光).xlsx"),OUT tchs, MAX_PATH); if (PathFileExists(tchs)) { //開啟c:\\1.xls m_excel->OpenExcelFile(tchs); //m_excel->ShowInExcel(TRUE); } if (!m_excel->LoadSheet(_T("服飾"),1)) { return; } // TODO: 在此加入額外的初始設定 COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); //新建一個.xls檔案,並寫入資料 CWorkbooks books; books.AttachDispatch(CExcelOp::m_app.get_Workbooks()); CWorkbook book; book=books.Add(covOptional);//得到Workbook CWorksheets sheets; CWorksheet sheet; CRange usedRange; sheets=book.get_Worksheets(); sheet=sheets.get_Item(COleVariant((short)1)); CRange start_range = sheet.get_Range(COleVariant(_T("A1")),covOptional); start_range.put_Value2(COleVariant(_T("hanhan"))); int nRows = m_excel->GetRowCount(); int nCells = m_excel->GetColumnCount(); CString sCloth,sVal; int n=0; for (int i=1;i<nRows;i++) { sCloth = m_excel->GetCell(i,1); if (sCloth == _T("男裝")) { sVal = m_excel->GetCell(i,2); CRange write_range = start_range.get_Offset(COleVariant((long)n),COleVariant((long)0)) ; write_range.put_Value2((COleVariant)(_T("男裝"))); write_range.ReleaseDispatch(); write_range = start_range.get_Offset(COleVariant((long)n++),COleVariant((long)1)) ; write_range.put_Value2((COleVariant)(sVal)); write_range.ReleaseDispatch(); } }//for start_range.ReleaseDispatch(); book.SaveAs(COleVariant(_T("C:\\2.xlsx")),covOptional,covOptional, covOptional,covOptional,covOptional,0, covOptional,covOptional,covOptional,covOptional,covOptional); book.put_Saved(TRUE); //將Workbook的儲存狀態設定為已儲存,即不讓系統提示是否人工儲存 book.Close(covOptional,covOptional,covOptional);//關閉workbook物件 books.Close(); sheet.ReleaseDispatch();//釋放sheet物件 sheets.ReleaseDispatch(); //釋放sheets物件 book.ReleaseDispatch();//釋放workbook物件 books.ReleaseDispatch(); //釋放workbooks物件