1. 程式人生 > 實用技巧 >C++環境下讀取excel表格,親測可用

C++環境下讀取excel表格,親測可用

在VS2015環境中,個人對以下程式和步驟進行了測試,結果表明完全可以讀取excel資料。

相關的完整程式可以在https://download.csdn.net/download/cxd3341/12683449中獲取

以下為程式建立步驟:

1、新建MFC程式:

新建基於對話方塊的MFC程式:

單擊完成,即完成基於MFC對話方塊的程式的建立。

2.新增讀取excel資料的介面類:

新增讀取excel的介面類:

3、新增完成後,找到這幾個介面類的標頭檔案,註釋/刪除 下圖紅框中的引入語句

注意:每個介面類的標頭檔案都需進行處理。

4、新增原始檔

excel.h檔案:

#pragma once
#include "CApplication.h"
#include "CRange.h"
#include "CWorkbook.h"
#include "CWorkbooks.h"
#include "CWorksheet.h"
#include "CWorksheets.h"
#include "stdafx.h"

class Excel
{
public:
	Excel();
	~Excel();

	void show(bool bShow);
	//檢查一個cell是否為字串
	bool isCellString(long iRow, long iColumn);
	//檢查一個cell是否為數值
	bool isCellInt(long iRow, long iColumn);
	//得到一個cell的string
	CString getCellString(long iRow, long iColumn);
	//得到一個cell的總數
	int getCellInt(long iRow, long iColumn);
	//得到一個cell的double資料
	double getCellDouble(long iRow, long iColumn);
	//取得行的總數
	int getRowCount();
	//取得列的總數
	int getColumnCount();
	//使用某個shell
	bool loadSheet(long tableId, bool preLoaded = false);
	bool loadSheet(CString sheet, bool preLoaded = false);

	//通過序號取得某個sheet的名稱
	CString getSheetName(long tableID);

	//得到sheet的總數
	int getSheetCount();

	//開啟excel檔案
	bool open(const char* fileName);

	//關閉開啟的excel檔案
	void close(bool ifSave = false);

	//另存為一個excel檔案
	void saveAsXLSFile(const CString &xlsFile);

	//取得開啟檔案的名稱
	CString getOpenFileName();

	//取得開啟sheel的名稱
	CString getOpenSheelName();

	//向cell中寫入一個int值
	void setCellInt(long iRow, long iColumn, int newInt);

	//向cell中寫入一個字串
	void setCellString(long iRow, long iColumn, CString newString);

public:
	//初始化 Excel_OLE
	static bool initExcel();

	//釋放Excel_OLE
	static void release();

	//取得列的名稱
	static char* getColumnName(long iColumn);

protected:
	void preLoadSheet();

private:
	CString openFileName;
	CWorkbook workBook;           //當前處理的檔案
	CWorkbooks books;             //ExcelBook集合,多檔案時使用
	CWorksheet workSheet;         //當前使用sheet
	CWorksheets sheets;           //Excel的sheet集合
	CRange currentRange;           //當前操作區域

	bool isLoad;                   //是否已經載入了某個sheet資料
	COleSafeArray safeArray;

protected:
	static CApplication application;   //Excel程序例項
};

excel.cpp檔案

//Excel.cpp
#include "stdafx.h"
#include <tchar.h>
#include "Excel.h"


COleVariant
covTrue((short)TRUE),
covFalse((short)FALSE),
covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);

CApplication Excel::application;

Excel::Excel() :isLoad(false)
{
}


Excel::~Excel()
{
	//close();
}


bool Excel::initExcel()
{
	//建立Excel 2000伺服器(啟動Excel)   
	if (!application.CreateDispatch(_T("Excel.application"), nullptr))
	{
		MessageBox(nullptr, _T("建立Excel服務失敗,你可能沒有安裝EXCEL,請檢查!"), _T("錯誤"), MB_OK);
		return FALSE;
	}

	application.put_DisplayAlerts(FALSE);
	return true;
}


void Excel::release()
{
	application.Quit();
	application.ReleaseDispatch();
	application = nullptr;
}

bool Excel::open(const char*  fileName)
{

	//先關閉檔案
	close();

	//利用模板建立新文件
	books.AttachDispatch(application.get_Workbooks(), true);


	LPDISPATCH lpDis = nullptr;
	lpDis = books.Add(COleVariant(CString(fileName)));

	if (lpDis)
	{
		workBook.AttachDispatch(lpDis);

		sheets.AttachDispatch(workBook.get_Worksheets());

		openFileName = fileName;
		return true;
	}

	return false;
}

void Excel::close(bool ifSave)
{
	//如果檔案已經開啟,關閉檔案
	if (!openFileName.IsEmpty())
	{
		//如果儲存,交給使用者控制,讓使用者自己存,如果自己SAVE,會出現莫名的等待  
		if (ifSave)
		{
			//show(true);
		}
		else
		{
			workBook.Close(COleVariant(short(FALSE)), COleVariant(openFileName), covOptional);
			books.Close();
		}

		//清空開啟檔名稱
		openFileName.Empty();
	}


	sheets.ReleaseDispatch();
	workSheet.ReleaseDispatch();
	currentRange.ReleaseDispatch();
	workBook.ReleaseDispatch();
	books.ReleaseDispatch();
}

void Excel::saveAsXLSFile(const CString &xlsFile)
{
	workBook.SaveAs(COleVariant(xlsFile),
		covOptional,
		covOptional,
		covOptional,
		covOptional,
		covOptional,
		0,
		covOptional,
		covOptional,
		covOptional,
		covOptional,
		covOptional);
	return;
}


int Excel::getSheetCount()
{
	return sheets.get_Count();
}

CString Excel::getSheetName(long tableID)
{
	CWorksheet sheet;
	sheet.AttachDispatch(sheets.get_Item(COleVariant((long)tableID)));
	CString name = sheet.get_Name();
	sheet.ReleaseDispatch();
	return name;
}


void Excel::preLoadSheet()
{
	CRange used_range;

	used_range = workSheet.get_UsedRange();


	VARIANT ret_ary = used_range.get_Value2();
	if (!(ret_ary.vt & VT_ARRAY))
	{
		return;
	}
	//  
	safeArray.Clear();
	safeArray.Attach(ret_ary);
}

//按照名稱載入sheet表格,也可提前載入所有表格
bool Excel::loadSheet(long tableId, bool preLoaded)
{
	LPDISPATCH lpDis = nullptr;
	currentRange.ReleaseDispatch();
	currentRange.ReleaseDispatch();
	lpDis = sheets.get_Item(COleVariant((long)tableId));
	if (lpDis)
	{
		workSheet.AttachDispatch(lpDis, true);
		currentRange.AttachDispatch(workSheet.get_Cells(), true);
	}
	else
	{
		return false;
	}

	isLoad = false;
	//如果進行預先載入  
	if (preLoaded)
	{
		preLoadSheet();
		isLoad = true;
	}

	return true;
}


bool Excel::loadSheet(CString sheet, bool preLoaded)
{
	LPDISPATCH lpDis = nullptr;
	currentRange.ReleaseDispatch();
	currentRange.ReleaseDispatch();

	lpDis = sheets.get_Item(COleVariant(sheet));
	if (lpDis)
	{
		workSheet.AttachDispatch(lpDis, true);
		currentRange.AttachDispatch(workSheet.get_Cells(), true);
	}
	else
	{
		return false;
	}

	isLoad = false;
	//如果進行預先載入  
	if (preLoaded)
	{
		preLoadSheet();
		isLoad = true;
	}

	return true;
}


int Excel::getColumnCount()
{
	CRange range;
	CRange usedRange;

	usedRange.AttachDispatch(workSheet.get_UsedRange(), true);
	range.AttachDispatch(usedRange.get_Columns(), true);
	int count = range.get_Count();

	usedRange.ReleaseDispatch();
	range.ReleaseDispatch();

	return count;
}

int Excel::getRowCount()
{
	CRange range;
	CRange usedRange;

	usedRange.AttachDispatch(workSheet.get_UsedRange(), true);
	range.AttachDispatch(usedRange.get_Rows(), true);

	int count = range.get_Count();

	usedRange.ReleaseDispatch();
	range.ReleaseDispatch();

	return count;
}

bool Excel::isCellString(long iRow, long iColumn)
{
	CRange range;
	range.AttachDispatch(currentRange.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;
}


bool Excel::isCellInt(long iRow, long iColumn)
{

	CRange range;
	range.AttachDispatch(currentRange.get_Item(COleVariant((long)iRow), COleVariant((long)iColumn)).pdispVal, true);
	COleVariant vResult = range.get_Value2();
	//VT_BSTR標示字串  
	if (vResult.vt == VT_INT || vResult.vt == VT_R8)
	{
		return true;
	}
	return false;
}

CString Excel::getCellString(long iRow, long iColumn)
{
	COleVariant vResult;
	CString str;
	//字串  
	if (isLoad == false)
	{
		CRange range;
		range.AttachDispatch(currentRange.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;
		safeArray.GetElement(read_address, &val);
		vResult = val;
	}

	if (vResult.vt == VT_BSTR)
	{
		str = vResult.bstrVal;
	}
	//整數  
	else if (vResult.vt == VT_INT)
	{
		str.Format(_T("%d"), vResult.pintVal);
	}
	//8位元組的數字   
	else if (vResult.vt == VT_R8)
	{
		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 = "";
	}

	return str;
}

double Excel::getCellDouble(long iRow, long iColumn)
{
	double rtn_value = 0;
	COleVariant vresult;
	//字串  
	if (isLoad == false)
	{
		CRange range;
		range.AttachDispatch(currentRange.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;
		safeArray.GetElement(read_address, &val);
		vresult = val;
	}

	if (vresult.vt == VT_R8)
	{
		rtn_value = vresult.dblVal;
	}

	return rtn_value;
}

int Excel::getCellInt(long iRow, long iColumn)
{
	int num;
	COleVariant vresult;

	if (isLoad == FALSE)
	{
		CRange range;
		range.AttachDispatch(currentRange.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;
		safeArray.GetElement(read_address, &val);
		vresult = val;
	}
	//  
	num = static_cast<int>(vresult.dblVal);

	return num;
}

void Excel::setCellString(long iRow, long iColumn, CString newString)
{
	COleVariant new_value(newString);
	CRange start_range = workSheet.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();
}

void Excel::setCellInt(long iRow, long iColumn, int newInt)
{
	COleVariant new_value((long)newInt);
	CRange start_range = workSheet.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();
}


void Excel::show(bool bShow)
{
	application.put_Visible(bShow);
	application.put_UserControl(bShow);
}

CString Excel::getOpenFileName()
{
	return openFileName;
}

CString Excel::getOpenSheelName()
{
	return workSheet.get_Name();
}

char* Excel::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;
}

5、在對話方塊中新增按鈕和靜態文字框:

為靜態文字框IDC_STATIC1控制元件新增控制元件變數

在readexcelDlg.h中新增對excel類的引用,

在readexcelDlg.h中宣告一個excel類的物件

Excel excel;

編譯程式,可能會彈出如下的錯誤:

在DialogBox前加下劃線即:_DialogBox (具體原理不知道)

再次編譯就OK了。

6、使用excel類

在button的單擊事件中完成下述程式碼:

void CreadexcelDlg::OnBnClickedButton1()
{
	// TODO: 在此新增控制元件通知處理程式程式碼
	//使用excel類
	bool bInit = m_excel.initExcel();
	char path[MAX_PATH];
	GetCurrentDirectoryA(MAX_PATH, path);//獲取當前工作目錄
	strcat_s(path,"\\data\\001.xlsx");//設定要開啟檔案的完整路徑

	bool bRet = m_excel.open(path);//開啟excel檔案

	CString strSheetName = m_excel.getSheetName(1);//獲取sheet名
	m_sheetname.SetWindowTextW(strSheetName);      //顯示讀取excel的資料表名

	bool bLoad = m_excel.loadSheet(strSheetName);//裝載sheet
	int nRow = m_excel.getRowCount();//獲取sheet中行數
	int nCol = m_excel.getColumnCount();//獲取sheet中列數

	CString cell;
	for (int i = 1; i <= nRow; ++i)
	{
		for (int j = 1; j <= nCol; ++j)
		{
			cell = m_excel.getCellString(i, j);
		}
	}
}

下圖為專案資料夾下data資料夾中的excel檔案001.xlsx

7、執行程式,結果如下圖所示,成功讀取excel資料表的相關資訊。

注:文章轉自如下地址

https://blog.csdn.net/cxd3341/article/details/107779314?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param