VS2010 C++ 操作Excel表格的编程实现

https://www.cnblogs.com/kernel0815/p/3318182.html

转载请注明原文网址:

 

http://www.cnblogs.com/xianyunhe/archive/2011/09/25/2190485.html

 

通过VC实现对Excel表格的操作的方法有多种,如:通过ODBC数据库实现,通过解析Excel表格文件,通过OLE/COM的实现。本文主要研究通过OLE/COM实现对Excel表格的操作。

  

本文源码的应用环境说明:

Windows XP SP3

Microsoft Visual Studio 2010

Microsoft Office Excel 2007

  

1、添加OLE/COM支持。

首先,应用程序必须添加对OLE/COM的支持,才能导入OLE/COM组件。

本文使用的是MFC对话框程序,在创建工程的向导中选中Automation选项即可为程序自动添加相应的头文件和OLE库初始化代码。

通过查看源代码,可以知道在stdafx.h的头文件中,添加了OLE/COM很多类所需添加的头文件。

#include <afxdisp.h>        // MFC 自动化类

同时,在应用程序类的InitInstance函数中,添加了OLE/COM的初始化代码,如下所示:

// 初始化 OLE 库

if (!AfxOleInit())

{

AfxMessageBox(IDP_OLE_INIT_FAILED);

return FALSE;

}

  

2、导入并封装Excel中的接口

Excel作为OLE/COM库插件,定义好了各类交互的接口,这些接口是跨语言的接口。VC可以通过导入这些接口,并通过接口来对Excel的操作。

由于本文只关心对Excel表格中的数据的读取,主要关注几个_Application、Workbooks、_Workbook、Worksheets、_Worksheet、Range等几个接口。Excel的各类接口的属性、方法可以通过MSDN的Office Development进行查询。

VS2010导入OLE/COM组件的接口的步骤为:Project->Class Wizard->Add Class->MFC Class From TypeLib,先选择要导入的组件所在的路径,即Excel.exe所在的路径,然后再选择

要导入的Excel类型库中的接口。

在完成接口导入后,VS2010将自动为导入的接口创建相应的实现类,用于对接口属性和方法的实现。由于标准的C++没有属性访问器,只能添加一个两个存取函数来实现对属性的访问,通过在属性名称前加上get_和put_前缀分别实现对属性的读写操作。即,由VC自动完成C++类对接口的封装。

  

本文所导入的接口对应的类和头文件的说明如下所示:

  

Excel接口

导入类

头文件

说明

_Application

CApplicaton

Application.h

Excel应用程序。

Workbooks

CWorkbooks

Workbooks.h

工作簿的容器,里面包括了Excel应用程序打开的所有工作簿。

_Workbook

CWorkbook

Workbook.h

单个工作簿。

Worksheets

CWorksheets

Worksheets.h

单个工作簿中的Sheet表格的容器,包括该工作簿中的所有Sheet。

_Worksheet

CWorksheet

Worksheet.h

单个Sheet表格。

Range

CRange

Range.h

一定数量的单元格,可对单元格进行单个或多个单元格进行操作。

  

3、导入Excel的整个类型库

接口对应类只是对接口的属性和方法进行了封装,而Excel中的数据类型,如枚举类型却并为并不能使用,因此,为了更方便的操作Excel,还需要导入Excel的数据类型。

通过查看导入接口对应的头文件可以发现,在所有导入接口的头文件中,都会有这么行:

#import "D:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE" no_namespace

这行代码的作用是导入Excel整个类型库到工程中。

由VS2010自动产生的导入代码存在以下几个问题:

(1)如果导入了多个接口,每个头文件都会把类型库导入一次,如果引用多个头文件,会导致类型库重复导入。

(2)Excel类型库中有些类型会跟MFC类库的某些类型冲突。

(3)Excel类型库的某些类型跟其他Office和VB的某些库相关,如果不导入相关库,将导致这些类型无法使用。。

以上三点问题的解决方法如下:

(1)仅在_Application接口对应头文件中导入Excel类型库。

(2)对冲突的类型进行重命名。

(3)在导入Excel类型库之前,先导入Office和VB的相关库。

更改后的导入类型库的代码如下:

  

/*导入Office的类型库*/

#import "C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE12\\MSO.DLL" \

rename("RGB", "MSORGB") \

rename("DocumentProperties", "MSODocumentProperties")

using namespace Office;

  

/*导入VB的类型库*/

#import "C:\\Program Files\\Common Files\\Microsoft Shared\\VBA\\VBA6\\VBE6EXT.OLB"

using namespace VBIDE;

  

/*导入Excel的类型库*/

#import "D:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE" \

rename("DialogBox", "ExcelDialogBox") \

rename("RGB", "ExcelRGB") \

rename("CopyFile", "ExcelCopyFile") \

rename("ReplaceText", "ExcelReplaceText") \

no_auto_exclude

Using namespace Excel;

  

编译程序后,会在Debug或Release目录下生成三个文件mso.tlh、vbe6ext.tlh和excel.tlh。通过打开文件可知,该三个文件的命名空间分别是Office、VBIDE和Excel。导入了Excel的整个类型库后,就可以使用Excel中的所有类型了。

  

4、操作Excel步骤

操作Excel的主要步骤如下:

(1)创建一个Excel应用程序。

(2)得到Workbook的容器。

(3)打开一个Workbook或者创建一个Workbook。

(4)得到Workbook中的Worksheet的容器。

(5)打开一个Worksheet或者创建一个WorkSheet。

(6)通过Range对WorkSheet中的单元格进行读写操作。

(7)保存Excel。

(8)释放资源。

  

5、批量处理Excel表格

VC通过OLE/COM操作Excel,是通过进程间的组件技术。因此,每次读写Excel中的单元格时,都要进行进程间的切换。当数据量大,如果一个单元格一个单元格的读取,主要的时间都花费在进程切换中。因此读取多个单元格,将可有效的提高程序的运行效率。

对多个单元格的读写操作可以通过CRange中以下两个成员函数来完成。

VARIANT get_Value2();

void put_Value2(VARIANT& newValue);

其中,输入参数newValue只要输入一个二维数组,即可实现向Excel中一次写入多个单元格的值。

其中,VARIANT中实现二维数据的方法可参考

http://www.cnblogs.com/xianyunhe/archive/2011/09/13/2174703.html

当然,在对CRange类进行操作之前,要设置CRange类对应的单元格。

  

6、Excel表格的保存

(1)如果要保存打开的工作簿,使用CWorkbook类的Save函数就可以保存工作簿,原文件将被覆盖。

(2)如果是新创建的工作簿,或者是要另存为,可使用CWorkbook类的SaveAs函数。

SaveAs的参数比较多。其中,第1个参数是设置要保存文件的路径;第2个参数是设置文件的格式,可在MSDN中查看枚举类型XlFileFormat来了解Excel的文件格式。经过测试,在本文所用的测试环境中,Excel2003的文件格式是xlExcel8,Excel2007的文件格式是xlExcel4。

  

7、获取当前Excel的版本

可以通过CApplication的get_Version函数来获得Excel的版本,其中,Excel2007的主版本号是12,Excel2003的主版本号是11。

  

8、示例源代码

主要代码如下:

  

 

 

    m_ListCtrl.SetExtendedStyle(LVS_REPORT | LVS_EX_FULLROWSELECT);

 

    CApplication ExcelApp;

    CWorkbooks books;

    CWorkbook book;

    CWorksheets sheets;

    CWorksheet sheet;

    CRange range;

    LPDISPATCH lpDisp = NULL;

 

    //创建Excel 服务器(启动Excel)

    if(!ExcelApp.CreateDispatch(_T("Excel.Application"),NULL))

    {

        AfxMessageBox(_T("启动Excel服务器失败!"));

        return -1;

    }

 

    /*判断当前Excel的版本*/

    CString strExcelVersion = ExcelApp.get_Version();

    int iStart = 0;

    strExcelVersion = strExcelVersion.Tokenize(_T("."), iStart);

    if (_T("11") == strExcelVersion)

    {

        AfxMessageBox(_T("当前Excel的版本是2003。"));

    }

    else if (_T("12") == strExcelVersion)

    {

        AfxMessageBox(_T("当前Excel的版本是2007。"));

    }

    else

    {

        AfxMessageBox(_T("当前Excel的版本是其他版本。"));

    }

 

    ExcelApp.put_Visible(TRUE);

    ExcelApp.put_UserControl(FALSE);

 

    /*得到工作簿容器*/

    books.AttachDispatch(ExcelApp.get_Workbooks());

 

    /*打开一个工作簿,如不存在,则新增一个工作簿*/

    CString strBookPath = _T("C:\\tmp.xls");

    try

    {

        /*打开一个工作簿*/

        lpDisp = books.Open(strBookPath,

            vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,

            vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,

            vtMissing, vtMissing, vtMissing, vtMissing);

        book.AttachDispatch(lpDisp);

    }

    catch(...)

    {

        /*增加一个新的工作簿*/

        lpDisp = books.Add(vtMissing);

        book.AttachDispatch(lpDisp);

    }

     

 

    /*得到工作簿中的Sheet的容器*/

    sheets.AttachDispatch(book.get_Sheets());

 

    /*打开一个Sheet,如不存在,就新增一个Sheet*/

    CString strSheetName = _T("NewSheet");

    try

    {

        /*打开一个已有的Sheet*/

        lpDisp = sheets.get_Item(_variant_t(strSheetName));

        sheet.AttachDispatch(lpDisp);

    }

    catch(...)

    {

        /*创建一个新的Sheet*/

        lpDisp = sheets.Add(vtMissing, vtMissing, _variant_t((long)1), vtMissing);

        sheet.AttachDispatch(lpDisp);

        sheet.put_Name(strSheetName);

    }

 

    system("pause");

 

    /*向Sheet中写入多个单元格,规模为10*10 */

    lpDisp = sheet.get_Range(_variant_t("A1"), _variant_t("J10"));

    range.AttachDispatch(lpDisp);

 

    VARTYPE vt = VT_I4; /*数组元素的类型,long*/

    SAFEARRAYBOUND sabWrite[2]; /*用于定义数组的维数和下标的起始值*/

    sabWrite[0].cElements = 10;

    sabWrite[0].lLbound = 0;

    sabWrite[1].cElements = 10;

    sabWrite[1].lLbound = 0;

 

    COleSafeArray olesaWrite;

    olesaWrite.Create(vt, sizeof(sabWrite)/sizeof(SAFEARRAYBOUND), sabWrite);

 

    /*通过指向数组的指针来对二维数组的元素进行间接赋值*/

    long (*pArray)[2] = NULL;

    olesaWrite.AccessData((void **)&pArray);

    memset(pArray, 0, sabWrite[0].cElements * sabWrite[1].cElements * sizeof(long));

 

    /*释放指向数组的指针*/

    olesaWrite.UnaccessData();

    pArray = NULL;

 

    /*对二维数组的元素进行逐个赋值*/

    long index[2] = {0, 0};

    long lFirstLBound = 0;

    long lFirstUBound = 0;

    long lSecondLBound = 0;

    long lSecondUBound = 0;

    olesaWrite.GetLBound(1, &lFirstLBound);

    olesaWrite.GetUBound(1, &lFirstUBound);

    olesaWrite.GetLBound(2, &lSecondLBound);

    olesaWrite.GetUBound(2, &lSecondUBound);

    for (long i = lFirstLBound; i <= lFirstUBound; i++)

    {

        index[0] = i;

        for (long j = lSecondLBound; j <= lSecondUBound; j++)

        {

            index[1] = j;

            long lElement = i * sabWrite[1].cElements + j;

            olesaWrite.PutElement(index, &lElement);

        }

    }

 

    /*把ColesaWritefeArray变量转换为VARIANT,并写入到Excel表格中*/

    VARIANT varWrite = (VARIANT)olesaWrite;

    range.put_Value2(varWrite);

 

    system("pause");

 

    /*根据文件的后缀名选择保存文件的格式*/

     CString strSaveAsName = _T("C:\\new.xlsx");

    CString strSuffix = strSaveAsName.Mid(strSaveAsName.ReverseFind(_T('.')));

    XlFileFormat NewFileFormat = xlOpenXMLWorkbook;

    if (0 == strSuffix.CompareNoCase(_T(".xls")))

    {

        NewFileFormat = xlExcel8;

    }

    book.SaveAs(_variant_t(strSaveAsName), _variant_t((long)NewFileFormat), vtMissing, vtMissing, vtMissing,

        vtMissing, 0, vtMissing, vtMissing, vtMissing,

        vtMissing, vtMissing);

 

    system("pause");

 

    /*读取Excel表中的多个单元格的值,在listctrl中显示*/

    VARIANT varRead = range.get_Value2();

    COleSafeArray olesaRead(varRead);

 

    VARIANT varItem;

    CString strItem;

    lFirstLBound = 0;

    lFirstUBound = 0;

    lSecondLBound = 0;

    lSecondUBound = 0;

    olesaRead.GetLBound(1, &lFirstLBound);

    olesaRead.GetUBound(1, &lFirstUBound);

    olesaRead.GetLBound(2, &lSecondLBound);

    olesaRead.GetUBound(2, &lSecondUBound);

    memset(index, 0, 2 * sizeof(long));

    m_ListCtrl.InsertColumn(0, _T(""), 0, 100);

    for (long j = lSecondLBound; j<= lSecondUBound; j++)

    {

        CString strColName = _T("");

        strColName.Format(_T("%d"), j);

        m_ListCtrl.InsertColumn(j, strColName, 0, 100);

    }

    for (long i = lFirstLBound; i <= lFirstUBound; i++)

    {

        CString strRowName = _T("");

        strRowName.Format(_T("%d"), i);

        m_ListCtrl.InsertItem(i-1, strRowName);

 

        index[0] = i;

        for (long j = lSecondLBound; j <= lSecondUBound; j++)

        {

            index[1] = j;

            olesaRead.GetElement(index, &varItem);

 

            switch (varItem.vt)

            {

            case VT_R8:

                {

                    strItem.Format(_T("%d"), (int)varItem.dblVal);

                }

 

            case VT_BSTR:

                {

                    strItem = varItem.bstrVal;

                }

 

            case VT_I4:

                {

                    strItem.Format(_T("%ld"), (int)varItem.lVal);

                }

 

            default:

                {

 

                }

            }

 

            m_ListCtrl.SetItemText(i-1, j, strItem);

        }

    }

 

 

 

    /*释放资源*/

    sheet.ReleaseDispatch();

    sheets.ReleaseDispatch();

    book.ReleaseDispatch();

    books.ReleaseDispatch();

    ExcelApp.Quit();

    ExcelApp.ReleaseDispatch();

 

 

示例源代码的工程文件的下载链接如下:

http://files.cnblogs.com/xianyunhe/ReadWriteExcel.rar

  

参考资料

(1)http://www.cnblogs.com/xianyunhe/archive/2011/09/13/2174703.html

(2)http://hfp0601.blog.163.com/blog/static/228483522011031104718762/

(3)http://www.cppblog.com/sleepwom/archive/2009/10/03/97804.html

(4)http://www.rondebruin.nl/saveas.htm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C 的 Excel 表格读取可以通过使用编程语言中的 Excel 相关库或者软件来实现。以下是几种常见的方法: 1. 使用 Python 的 pandas 库:可以通过 pandas 库的 read_excel() 函数来读取 Excel 表格。首先,需要安装 pandas 库,然后在代码中导入 pandas 库,使用 read_excel() 函数读取 Excel 文件,并将数据存储到变量中进行后续处理。 2. 使用 Java 的 Apache POI 库:Apache POI 是一个开源的 Java 库,用于操作 Microsoft Office 文件格式,其中包括 Excel 文件。可以使用 Apache POI 提供的 API 来读取 Excel 表格。首先,需要在 Java 项目中引入 Apache POI 的相关依赖,然后使用 Java 代码调用相应的 API 来读取 Excel 文件中的数据。 3. 使用 VBA:Excel 自带的 VBA(Visual Basic for Applications)可以用于编写宏,实现Excel 表格的读取。通过在 Excel 中开启开发者模式,并在 VBA 编辑器中编写相应的代码,可以读取指定的 Excel 文件并将数据存储或处理。 不论使用哪种方法,都需要指定要读取的 Excel 文件的路径,并根据文件中的具体结构和需求,选择相应的读取方式和处理方式。读取 Excel 表格后,可以对数据进行分析、处理、转换等操作,以满足具体的业务需求。 ### 回答2: 在Excel中读取C的表格,首先需要打开Excel软件并创建一个新的工作簿。然后,点击“文件”菜单,选择“打开”选项,浏览文件夹并找到C所在的位置。双击C的文件,Excel会自动将其加载到工作簿中。 在Excel中,以表格形式显示的数据被组织成行和列,其中行是水平方向的,列是垂直方向的。C的表格中的每一行代表一个记录,而每一列代表记录的一个属性。 要获取C表格中的数据,可以在工作簿中选择一个单元格,该单元格对应于C表格中的某个位置。然后,可以使用Excel提供的函数和命令来处理和操作该单元格及其周围的单元格。 例如,可以使用公式来计算单元格的值,如SUM(求和)、AVERAGE(求平均值)、MAX(求最大值)、MIN(求最小值)等。还可以使用条件函数如IF(条件判断)、COUNTIF(计数符合条件的单元格数量)等来对数据进行进一步的筛选和分析。 此外,Excel还提供了数据透视表(PivotTable)功能,可以快速分析和汇总大量数据。通过简单的拖拽和设置选项,可以对C表格中的数据进行多维度的聚合和展示。 最后,读取C表格的数据后,可以进行数据的导出和保存。通过选择“文件”菜单中的“另存为”选项,可以将文件保存为不同的格式,如Excel文件(.xlsx)、CSV文件(.csv)等,以方便其他软件和系统的使用。 总之,通过Excel的强大功能和灵活性,我们能够方便地读取和处理C的表格数据,并进行各种统计和分析操作。 ### 回答3: 在C语言中,我们可以使用第三方库来读取和处理Excel表格。其中一种常用的库是libxlsxwriter,它可以用于创建和修改Excel文件。下面是一个简单的代码示例,说明如何使用libxlsxwriter库来读取Excel表格中的数据。 ```c #include <xlsxwriter.h> #include <stdio.h> int main() { // 打开Excel文件 lxw_workbook *workbook = workbook_new("example.xlsx"); // 检查Excel文件是否打开成功 if (!workbook) { printf("无法打开Excel文件!\n"); return 1; } // 选择要读取的工作表 lxw_worksheet *worksheet = workbook_get_worksheet(workbook, 0); // 第一个工作表的索引为0 // 读取单元格的值 lxw_cell *cell = worksheet_find_cell(worksheet, 0, 0); // 第一个单元格的索引为(0,0) if (cell) { printf("A1单元格的值为:%s\n", lxw_cell_get_string(cell)); } else { printf("未找到单元格!\n"); } // 关闭Excel文件 workbook_close(workbook); return 0; } ``` 需要注意的是,使用libxlsxwriter库读取Excel表格需要先安装该库并将其链接到编译器中。可以使用以下命令来安装libxlsxwriter: ``` $ git clone https://github.com/jmcnamara/libxlsxwriter.git $ cd libxlsxwriter $ make $ sudo make install ``` 接下来,编译和运行上述代码: ``` $ gcc -o read_excel read_excel.c -lxlsxwriter $ ./read_excel ``` 以上代码中给出了一个简单的例子,读取了Excel表格中A1单元格的值。您可以根据实际需求修改代码以读取其他单元格或批量读取表格数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值