VC++ 读写 Excel 文件实现

一、开发环境配置

1.1 开发环境要求

复制代码
操作系统:Windows 7/10/11
开发工具:Visual Studio 2015/2017/2019/2022
字符集:Unicode
平台:Win32/x64

1.2 第三方库选择

推荐使用 libxl 库(无需安装 Excel,直接读写 .xls/.xlsx 文件):

  • 官网:https://www.libxl.com/
  • 下载:libxl-4.0.4.0(稳定版本)
  • 优点:无需安装 Office,读写速度快,支持 Unicode

二、项目配置

2.1 Visual Studio 项目配置

(1)包含目录设置
复制代码
项目属性 → C/C++ → 常规 → 附加包含目录
添加:D:\libxl-4.0.4.0\include_cpp
(2)库目录设置
复制代码
项目属性 → 链接器 → 常规 → 附加库目录
添加:D:\libxl-4.0.4.0\lib\vc2015
(3)链接库设置
复制代码
项目属性 → 链接器 → 输入 → 附加依赖项
添加:libxl.lib
(4)复制 DLL 文件
复制代码
将 libxl.dll 复制到:
• 项目目录\Debug\
• 项目目录\Release\
• 或 System32/SysWOW64(系统级)

三、源码实现

3.1 Excel 操作封装类 (ExcelHelper.h)

cpp 复制代码
#ifndef __EXCEL_HELPER_H__
#define __EXCEL_HELPER_H__

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include "libxl.h"

#pragma comment(lib, "libxl.lib")

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

    // 文件操作
    bool CreateNewFile(const std::wstring& filePath);
    bool OpenExistingFile(const std::wstring& filePath);
    bool SaveFile();
    bool SaveAsFile(const std::wstring& filePath);
    void CloseFile();

    // Sheet 操作
    int  AddSheet(const std::wstring& sheetName);
    bool SelectSheet(int sheetIndex);
    bool DeleteSheet(int sheetIndex);
    int  GetSheetCount();
    std::wstring GetSheetName(int sheetIndex);

    // 单元格读写
    bool WriteCellString(int row, int col, const std::wstring& value);
    bool WriteCellNumber(int row, int col, double value);
    bool WriteCellInteger(int row, int col, int value);
    bool WriteCellFormula(int row, int col, const std::wstring& formula);

    std::wstring ReadCellString(int row, int col);
    double ReadCellNumber(int row, int col);
    int ReadCellInteger(int row, int col);

    // 批量操作
    bool WriteRow(int row, const std::vector<std::wstring>& data);
    bool WriteColumn(int col, const std::vector<std::wstring>& data);
    bool ReadRow(int row, std::vector<std::wstring>& data);
    bool ReadColumn(int col, std::vector<std::wstring>& data);

    // 格式设置
    void SetCellFont(int row, int col, const std::wstring& fontName, int fontSize, bool bold = false);
    void SetCellAlignment(int row, int col, libxl::AlignH alignH, libxl::AlignV alignV);
    void SetCellBorder(int row, int col, libxl::BorderStyle style);
    void SetCellBackgroundColor(int row, int col, libxl::Color color);
    void AutoFitColumn(int col);

    // 行列操作
    void SetColumnWidth(int col, double width);
    void SetRowHeight(int row, double height);
    void MergeCells(int row1, int col1, int row2, int col2);

    // 数据验证
    bool IsCellEmpty(int row, int col);
    int  FindRowByValue(int col, const std::wstring& value);
    int  FindColByValue(int row, const std::wstring& value);

private:
    libxl::Book* m_book;
    libxl::Sheet* m_sheet;
    std::wstring m_filePath;
    bool m_isNewFile;
};

#endif // __EXCEL_HELPER_H__

3.2 Excel 操作封装实现 (ExcelHelper.cpp)

cpp 复制代码
#include "ExcelHelper.h"
#include <fstream>
#include <sstream>

ExcelHelper::ExcelHelper()
    : m_book(nullptr)
    , m_sheet(nullptr)
    , m_isNewFile(false)
{
    // 创建 Excel 工作簿对象
    m_book = xlCreateBook();
    if (m_book)
    {
        m_book->setKey(L"Your Name", L"Your License Key"); // 如果有许可证
    }
}

ExcelHelper::~ExcelHelper()
{
    CloseFile();
}

// 创建新文件
bool ExcelHelper::CreateNewFile(const std::wstring& filePath)
{
    CloseFile();
    
    if (!m_book)
    {
        m_book = xlCreateBook();
        if (!m_book) return false;
    }

    m_filePath = filePath;
    m_isNewFile = true;
    return true;
}

// 打开已有文件
bool ExcelHelper::OpenExistingFile(const std::wstring& filePath)
{
    CloseFile();
    
    if (!m_book)
    {
        m_book = xlCreateBook();
        if (!m_book) return false;
    }

    if (!m_book->load(filePath.c_str()))
    {
        std::wcerr << L"Failed to load file: " << filePath << std::endl;
        return false;
    }

    m_filePath = filePath;
    m_isNewFile = false;
    return true;
}

// 保存文件
bool ExcelHelper::SaveFile()
{
    if (!m_book || m_filePath.empty())
        return false;

    if (m_isNewFile)
    {
        return m_book->save(m_filePath.c_str());
    }
    else
    {
        return m_book->save(m_filePath.c_str());
    }
}

// 另存为
bool ExcelHelper::SaveAsFile(const std::wstring& filePath)
{
    if (!m_book)
        return false;

    return m_book->save(filePath.c_str());
}

// 关闭文件
void ExcelHelper::CloseFile()
{
    if (m_book)
    {
        m_book->release();
        m_book = nullptr;
    }
    m_sheet = nullptr;
    m_filePath.clear();
}

// 添加工作表
int ExcelHelper::AddSheet(const std::wstring& sheetName)
{
    if (!m_book)
        return -1;

    m_sheet = m_book->addSheet(sheetName.c_str());
    if (m_sheet)
        return m_book->sheetCount() - 1;
    
    return -1;
}

// 选择工作表
bool ExcelHelper::SelectSheet(int sheetIndex)
{
    if (!m_book || sheetIndex < 0 || sheetIndex >= m_book->sheetCount())
        return false;

    m_sheet = m_book->getSheet(sheetIndex);
    return (m_sheet != nullptr);
}

// 获取工作表数量
int ExcelHelper::GetSheetCount()
{
    return m_book ? m_book->sheetCount() : 0;
}

// 写入字符串
bool ExcelHelper::WriteCellString(int row, int col, const std::wstring& value)
{
    if (!m_sheet)
        return false;

    return m_sheet->writeStr(row, col, value.c_str());
}

// 写入数字
bool ExcelHelper::WriteCellNumber(int row, int col, double value)
{
    if (!m_sheet)
        return false;

    return m_sheet->writeNum(row, col, value);
}

// 写入整数
bool ExcelHelper::WriteCellInteger(int row, int col, int value)
{
    return WriteCellNumber(row, col, static_cast<double>(value));
}

// 写入公式
bool ExcelHelper::WriteCellFormula(int row, int col, const std::wstring& formula)
{
    if (!m_sheet)
        return false;

    return m_sheet->writeFormula(row, col, formula.c_str());
}

// 读取字符串
std::wstring ExcelHelper::ReadCellString(int row, int col)
{
    if (!m_sheet)
        return L"";

    const wchar_t* value = m_sheet->readStr(row, col);
    return value ? std::wstring(value) : L"";
}

// 读取数字
double ExcelHelper::ReadCellNumber(int row, int col)
{
    if (!m_sheet)
        return 0.0;

    return m_sheet->readNum(row, col);
}

// 读取整数
int ExcelHelper::ReadCellInteger(int row, int col)
{
    return static_cast<int>(ReadCellNumber(row, col));
}

// 写入整行
bool ExcelHelper::WriteRow(int row, const std::vector<std::wstring>& data)
{
    if (!m_sheet)
        return false;

    for (size_t col = 0; col < data.size(); ++col)
    {
        if (!WriteCellString(row, static_cast<int>(col), data[col]))
            return false;
    }
    return true;
}

// 写入整列
bool ExcelHelper::WriteColumn(int col, const std::vector<std::wstring>& data)
{
    if (!m_sheet)
        return false;

    for (size_t row = 0; row < data.size(); ++row)
    {
        if (!WriteCellString(static_cast<int>(row), col, data[row]))
            return false;
    }
    return true;
}

// 读取整行
bool ExcelHelper::ReadRow(int row, std::vector<std::wstring>& data)
{
    if (!m_sheet)
        return false;

    data.clear();
    int cols = 0;
    
    // 查找最后一列
    while (!IsCellEmpty(row, cols))
    {
        data.push_back(ReadCellString(row, cols));
        cols++;
    }
    
    return true;
}

// 读取整列
bool ExcelHelper::ReadColumn(int col, std::vector<std::wstring>& data)
{
    if (!m_sheet)
        return false;

    data.clear();
    int rows = 0;
    
    // 查找最后一行
    while (!IsCellEmpty(rows, col))
    {
        data.push_back(ReadCellString(rows, col));
        rows++;
    }
    
    return true;
}

// 设置字体
void ExcelHelper::SetCellFont(int row, int col, const std::wstring& fontName, int fontSize, bool bold)
{
    if (!m_sheet)
        return;

    libxl::Format* format = m_book->addFormat();
    if (format)
    {
        format->setFont(fontName.c_str());
        format->setFontSize(fontSize);
        format->setBold(bold);
        m_sheet->setColFormat(col, col, format);
    }
}

// 设置对齐方式
void ExcelHelper::SetCellAlignment(int row, int col, libxl::AlignH alignH, libxl::AlignV alignV)
{
    if (!m_sheet)
        return;

    libxl::Format* format = m_book->addFormat();
    if (format)
    {
        format->setAlignH(alignH);
        format->setAlignV(alignV);
        m_sheet->setColFormat(col, col, format);
    }
}

// 设置边框
void ExcelHelper::SetCellBorder(int row, int col, libxl::BorderStyle style)
{
    if (!m_sheet)
        return;

    libxl::Format* format = m_book->addFormat();
    if (format)
    {
        format->setBorder(style);
        m_sheet->setColFormat(col, col, format);
    }
}

// 自动调整列宽
void ExcelHelper::AutoFitColumn(int col)
{
    if (!m_sheet)
        return;

    m_sheet->setCol(col, col, -1); // -1 表示自动调整
}

// 设置列宽
void ExcelHelper::SetColumnWidth(int col, double width)
{
    if (!m_sheet)
        return;

    m_sheet->setCol(col, col, width);
}

// 设置行高
void ExcelHelper::SetRowHeight(int row, double height)
{
    if (!m_sheet)
        return;

    m_sheet->setRow(row, height);
}

// 合并单元格
void ExcelHelper::MergeCells(int row1, int col1, int row2, int col2)
{
    if (!m_sheet)
        return;

    m_sheet->setMerge(row1, row2, col1, col2);
}

// 判断单元格是否为空
bool ExcelHelper::IsCellEmpty(int row, int col)
{
    if (!m_sheet)
        return true;

    return m_sheet->isCellBlank(row, col);
}

// 查找行
int ExcelHelper::FindRowByValue(int col, const std::wstring& value)
{
    if (!m_sheet)
        return -1;

    for (int row = 0; row < m_sheet->lastRow(); ++row)
    {
        if (ReadCellString(row, col) == value)
            return row;
    }
    return -1;
}

// 查找列
int ExcelHelper::FindColByValue(int row, const std::wstring& value)
{
    if (!m_sheet)
        return -1;

    for (int col = 0; col < m_sheet->lastCol(); ++col)
    {
        if (ReadCellString(row, col) == value)
            return col;
    }
    return -1;
}

3.3 主程序示例 (main.cpp)

cpp 复制代码
#include "ExcelHelper.h"
#include <iostream>
#include <vector>

int main()
{
    std::cout << "=== Excel 文件读写测试 ===" << std::endl;

    ExcelHelper excel;

    // 1. 创建新文件
    std::wstring filePath = L".\\TestData.xlsx";
    if (!excel.CreateNewFile(filePath))
    {
        std::cerr << "创建 Excel 文件失败!" << std::endl;
        return -1;
    }

    // 2. 添加工作表
    int sheetIndex = excel.AddSheet(L"学生成绩表");
    if (sheetIndex < 0)
    {
        std::cerr << "创建工作表失败!" << std::endl;
        return -1;
    }

    // 3. 选择工作表
    if (!excel.SelectSheet(sheetIndex))
    {
        std::cerr << "选择工作表失败!" << std::endl;
        return -1;
    }

    // 4. 写入表头
    std::vector<std::wstring> headers = {
        L"学号", L"姓名", L"语文", L"数学", L"英语", L"总分"
    };
    
    if (!excel.WriteRow(0, headers))
    {
        std::cerr << "写入表头失败!" << std::endl;
        return -1;
    }

    // 5. 写入数据
    std::vector<std::vector<std::wstring>> students = {
        {L"001", L"张三", L"85", L"92", L"88", L"265"},
        {L"002", L"李四", L"78", L"96", L"82", L"256"},
        {L"003", L"王五", L"92", L"88", L"91", L"271"},
        {L"004", L"赵六", L"65", L"72", L"68", L"205"}
    };

    for (size_t i = 0; i < students.size(); ++i)
    {
        if (!excel.WriteRow(static_cast<int>(i + 1), students[i]))
        {
            std::cerr << "写入第 " << i + 1 << " 行失败!" << std::endl;
            return -1;
        }
    }

    // 6. 设置格式
    excel.SetCellFont(0, 0, L"Arial", 12, true);
    excel.SetCellAlignment(0, 0, libxl::ALIGNH_CENTER, libxl::ALIGNV_CENTER);
    excel.SetCellBorder(0, 0, libxl::BORDERSTYLE_THIN);
    excel.SetColumnWidth(0, 15);
    excel.AutoFitColumn(1);

    // 7. 合并单元格示例
    excel.MergeCells(6, 0, 6, 2);
    excel.WriteCellString(6, 0, L"班级平均分:");

    // 8. 保存文件
    if (!excel.SaveFile())
    {
        std::cerr << "保存文件失败!" << std::endl;
        return -1;
    }

    std::wcout << L"Excel 文件创建成功:" << filePath << std::endl;

    // 9. 读取测试
    std::cout << "\n=== 读取 Excel 文件测试 ===" << std::endl;
    
    if (!excel.OpenExistingFile(filePath))
    {
        std::cerr << "打开 Excel 文件失败!" << std::endl;
        return -1;
    }

    if (!excel.SelectSheet(0))
    {
        std::cerr << "选择工作表失败!" << std::endl;
        return -1;
    }

    // 读取表头
    std::vector<std::wstring> readHeaders;
    if (excel.ReadRow(0, readHeaders))
    {
        std::wcout << L"表头:";
        for (const auto& header : readHeaders)
        {
            std::wcout << header << L" ";
        }
        std::wcout << std::endl;
    }

    // 读取第一行数据
    std::vector<std::wstring> firstRow;
    if (excel.ReadRow(1, firstRow))
    {
        std::wcout << L"第一行数据:";
        for (const auto& cell : firstRow)
        {
            std::wcout << cell << L" ";
        }
        std::wcout << std::endl;
    }

    // 读取特定单元格
    std::wstring name = excel.ReadCellString(1, 1);
    double mathScore = excel.ReadCellNumber(1, 3);
    
    std::wcout << L"姓名:" << name << L",数学成绩:" << mathScore << std::endl;

    // 10. 查找测试
    int rowIndex = excel.FindRowByValue(1, L"王五");
    if (rowIndex >= 0)
    {
        std::wcout << L"找到王五在第 " << rowIndex + 1 << L" 行" << std::endl;
    }

    excel.CloseFile();
    std::cout << "\nExcel 操作完成!" << std::endl;

    return 0;
}

四、MFC 对话框应用示例

4.1 MFC 主对话框头文件 (ExcelDlg.h)

cpp 复制代码
#pragma once
#include "ExcelHelper.h"

class CExcelDlg : public CDialogEx
{
public:
    CExcelDlg(CWnd* pParent = nullptr);

protected:
    virtual void DoDataExchange(CDataExchange* pDX);
    virtual BOOL OnInitDialog();

    // 按钮事件
    afx_msg void OnBnClickedBtnCreate();
    afx_msg void OnBnClickedBtnOpen();
    afx_msg void OnBnClickedBtnSave();
    afx_msg void OnBnClickedBtnRead();
    afx_msg void OnBnClickedBtnWrite();

private:
    ExcelHelper m_excel;
    CString m_filePath;
    CListCtrl m_listCtrl;

    DECLARE_MESSAGE_MAP()
};

4.2 MFC 主对话框实现 (ExcelDlg.cpp)

cpp 复制代码
#include "stdafx.h"
#include "ExcelDlg.h"

BEGIN_MESSAGE_MAP(CExcelDlg, CDialogEx)
    ON_BN_CLICKED(IDC_BTN_CREATE, &CExcelDlg::OnBnClickedBtnCreate)
    ON_BN_CLICKED(IDC_BTN_OPEN, &CExcelDlg::OnBnClickedBtnOpen)
    ON_BN_CLICKED(IDC_BTN_SAVE, &CExcelDlg::OnBnClickedBtnSave)
    ON_BN_CLICKED(IDC_BTN_READ, &CExcelDlg::OnBnClickedBtnRead)
    ON_BN_CLICKED(IDC_BTN_WRITE, &CExcelDlg::OnBnClickedBtnWrite)
END_MESSAGE_MAP()

BOOL CExcelDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // 初始化列表控件
    m_listCtrl.SubclassDlgItem(IDC_LIST_DATA, this);
    m_listCtrl.InsertColumn(0, _T("学号"), LVCFMT_LEFT, 80);
    m_listCtrl.InsertColumn(1, _T("姓名"), LVCFMT_LEFT, 80);
    m_listCtrl.InsertColumn(2, _T("语文"), LVCFMT_LEFT, 60);
    m_listCtrl.InsertColumn(3, _T("数学"), LVCFMT_LEFT, 60);
    m_listCtrl.InsertColumn(4, _T("英语"), LVCFMT_LEFT, 60);

    return TRUE;
}

void CExcelDlg::OnBnClickedBtnCreate()
{
    CFileDialog dlg(FALSE, _T(".xlsx"), NULL, OFN_OVERWRITEPROMPT,
                   _T("Excel Files (*.xlsx)|*.xlsx|All Files (*.*)|*.*||"));
    
    if (dlg.DoModal() == IDOK)
    {
        m_filePath = dlg.GetPathName();
        
        if (m_excel.CreateNewFile((LPCTSTR)m_filePath))
        {
            int sheetIdx = m_excel.AddSheet(_T("学生成绩"));
            m_excel.SelectSheet(sheetIdx);
            
            // 写入表头
            std::vector<std::wstring> headers = {L"学号", L"姓名", L"语文", L"数学", L"英语"};
            m_excel.WriteRow(0, headers);
            
            MessageBox(_T("Excel 文件创建成功!"), _T("提示"), MB_ICONINFORMATION);
        }
    }
}

void CExcelDlg::OnBnClickedBtnOpen()
{
    CFileDialog dlg(TRUE, _T(".xlsx"), NULL, OFN_FILEMUSTEXIST,
                   _T("Excel Files (*.xlsx)|*.xlsx|All Files (*.*)|*.*||"));
    
    if (dlg.DoModal() == IDOK)
    {
        m_filePath = dlg.GetPathName();
        
        if (m_excel.OpenExistingFile((LPCTSTR)m_filePath))
        {
            m_excel.SelectSheet(0);
            MessageBox(_T("Excel 文件打开成功!"), _T("提示"), MB_ICONINFORMATION);
        }
    }
}

void CExcelDlg::OnBnClickedBtnSave()
{
    if (m_excel.SaveFile())
    {
        MessageBox(_T("文件保存成功!"), _T("提示"), MB_ICONINFORMATION);
    }
}

void CExcelDlg::OnBnClickedBtnWrite()
{
    // 从界面获取数据并写入 Excel
    CString studentId, name, chinese, math, english;
    
    GetDlgItemText(IDC_EDIT_ID, studentId);
    GetDlgItemText(IDC_EDIT_NAME, name);
    GetDlgItemText(IDC_EDIT_CHINESE, chinese);
    GetDlgItemText(IDC_EDIT_MATH, math);
    GetDlgItemText(IDC_EDIT_ENGLISH, english);

    int row = m_listCtrl.GetItemCount() + 1; // +1 跳过表头
    
    m_excel.WriteCellString(row, 0, (LPCTSTR)studentId);
    m_excel.WriteCellString(row, 1, (LPCTSTR)name);
    m_excel.WriteCellString(row, 2, (LPCTSTR)chinese);
    m_excel.WriteCellString(row, 3, (LPCTSTR)math);
    m_excel.WriteCellString(row, 4, (LPCTSTR)english);

    // 添加到列表控件
    int nItem = m_listCtrl.InsertItem(row - 1, studentId);
    m_listCtrl.SetItemText(nItem, 1, name);
    m_listCtrl.SetItemText(nItem, 2, chinese);
    m_listCtrl.SetItemText(nItem, 3, math);
    m_listCtrl.SetItemText(nItem, 4, english);

    MessageBox(_T("数据写入成功!"), _T("提示"), MB_ICONINFORMATION);
}

void CExcelDlg::OnBnClickedBtnRead()
{
    m_listCtrl.DeleteAllItems();
    
    std::vector<std::wstring> rowData;
    int row = 1; // 从第1行开始(跳过表头)
    
    while (m_excel.ReadRow(row, rowData) && !rowData.empty())
    {
        int nItem = m_listCtrl.InsertItem(row - 1, rowData[0].c_str());
        
        for (size_t col = 1; col < rowData.size(); ++col)
        {
            m_listCtrl.SetItemText(nItem, col, rowData[col].c_str());
        }
        
        row++;
        rowData.clear();
    }
    
    MessageBox(_T("数据读取成功!"), _T("提示"), MB_ICONINFORMATION);
}

参考代码 VC++读写Excel文件源代码 www.youwenfan.com/contentcsu/60836.html

五、编译与部署注意事项

5.1 常见编译错误解决

错误类型 解决方法
找不到 libxl.h 检查附加包含目录是否正确
找不到 libxl.lib 检查附加库目录和依赖项
无法打开 libxl.dll 将 DLL 复制到可执行文件目录
中文乱码 确保项目使用 Unicode 字符集
内存泄漏 确保正确调用 CloseFile()

5.2 替代方案

如果不想使用 libxl,可以考虑:

  1. ODBC:使用 Microsoft Jet 引擎(仅支持 .xls)
  2. ADO:ActiveX Data Objects(依赖 Office)
  3. CSV 格式:直接读写逗号分隔文件(最简单)
相关推荐
Lucky_ldy1 小时前
C语言学习:字符函数和字符串函数(内容丰富且易懂)
c语言·开发语言·学习
小小编程能手1 小时前
C++文件从操作:
开发语言·c++
fengyehongWorld1 小时前
Excel 函数式编程相关的公式
excel
czxyvX1 小时前
5-Qt系统相关
开发语言·qt
茉莉玫瑰花茶1 小时前
C++ 17 详细特性解析(6)
开发语言·c++
froginwe111 小时前
Bootstrap 标签页
开发语言
东方.既白1 小时前
QML与C++炫酷界面交互DEMO
开发语言·c++·交互
承渊政道1 小时前
【贪心算法】(经典实战应用解析(一):柠檬水找零、将数组和减半的最少操作次数、最大数、摆动序列)
数据结构·c++·学习·算法·leetcode·贪心算法·排序算法
脆皮炸鸡7551 小时前
大山之二:文件系统(Ext系列)
linux·开发语言·经验分享·学习方法