不知不觉已经加入CSDN很久了,但从来没有发过文章,最近开发了一个小工具踩了很多坑,主要是QT操作大数据Excel文件,现在和大家分享一下。

查阅了大部分资料,大数据读写excel文件用QAxObject对象最快,借鉴了一些读写excel文件的demo,所以本文也采用了这种方法。

对于代码的解释,大部分我都写在注释里了,有不明白或者建议的话,欢迎大家提出来。

话不多说,上代码。

完整项目代码GitHub地址:https://github.com/ChinaSweetMilk/qtexcel

读写单元格时,常用以下这种方法:

// 根据行号、列号读取某个单元格内容
QAxObject* pCell = m_pWorksheet->querySubObject("Cells(int, int)", iirow, icolumn);
QString    strCell = pCell->property("Value").toString();// 根据行列值读取某个单元格内容
QAxObject* pCell = pWorksheet->querySubObject("Range(QString)", strnumber);
QString    strCell = pCell->property("Value").toString();// 根据行号、列号写入某个单元格内容
QAxObject* pCell = m_pWorksheet->querySubObject("Cells(int, int)", irow, icolumn);
QString    pCell->setProperty("Value", strvalue);// 根据行列值读取某个单元格内容
QAxObject* pCell = m_pWorksheet->querySubObject("Range(QString)", strnumber);
QString    pCell->setProperty("Value", strvalue);

读取单个单元格内容时,可以使用以上方法,一秒大概能读写200行左右。但是需要大量读写单元格时,以上方法将会变得十分缓慢,所以这时需要用到QVariant,一次读取或写入整个工作表。采用以下方法,能将效率大大提高,一万行大概500毫秒。这个版本还没采用多线程读写,后面加入效率还可以提高。

以下是一次读取工作表全部内容的方法:

void ExcelOperator::readAll(QList<QList<QVariant> > &res)
{QVariant var;if (m_pWorksheet != NULL && ! m_pWorksheet->isNull()){// 获取该sheet的数据范围QAxObject * ax_usedRange = m_pWorksheet->querySubObject("UsedRange");if(NULL == ax_usedRange || ax_usedRange->isNull()){return;}// 获取该sheet的数据内容var = ax_usedRange->dynamicCall("Value");delete ax_usedRange;}this->castVariant2ListListVariant(var, res);return;
}void ExcelOperator::castVariant2ListListVariant(const QVariant &var, QList<QList<QVariant> > &res)
{QVariantList varRows = var.toList();if(varRows.isEmpty()){return;}const int rowCount = varRows.size();QVariantList rowData;for(int i=0;i<rowCount;++i){rowData = varRows[i].toList();res.push_back(rowData);}
}
以下是一次写入工作表全部内容的方法:
bool ExcelOperator::writeCurrentSheet(const QList<QList<QVariant> > &cells)
{if(cells.size() <= 0)return false;if(NULL == this->m_pWorksheet || this->m_pWorksheet->isNull())return false;// 获取写入内容行数int irow = cells.size();// 获取写入内容列数int icol = cells.at(0).size();QString strRang;// 获取写入矩形内容最右边列标识convertToColName(icol, strRang);// 获取写入矩形内容最右边右下角单元格标识strRang += QString::number(irow);// 获取写入矩形内容写入范围strRang = "A2:" + strRang;qDebug()<< strRang;QAxObject *range = this->m_pWorksheet->querySubObject("Range(const QString&)", strRang);if(NULL == range || range->isNull()){return false;}bool succ = false;QVariant var;castListListVariant2Variant(cells,var);// 将数据写入到sheetsucc = range->setProperty("Value", var);delete range;return succ;
}void ExcelOperator::castListListVariant2Variant(const QList<QList<QVariant> > &listcells, QVariant &varres)
{QVariantList vars;const int rows = listcells.size();for(int i = 0; i < rows; ++i){vars.append(QVariant(listcells[i]));}varres = QVariant(vars);
}void ExcelOperator::convertToColName(int idata, QString &strres)
{Q_ASSERT(idata > 0 && idata<65535);int tempData = idata / 26;if(tempData > 0){int mode = idata % 26;convertToColName(mode, strres);convertToColName(tempData, strres);}else{strres = (to26AlphabetString(idata)+ strres);}
}// 数字转换为26字母
QString ExcelOperator::to26AlphabetString(int idata)
{QChar ch = idata + 0x40; // A对应0x41return QString(ch);
}
一、简单应用demo
ExcelOperator * pexceloperator = new ExcelOperator;
QString strfilename = QFileDialog::getOpenFileName(this, tr("选择配置文件!"),".",tr("excel文件(*.xlsx)"));qDebug()<< "filename : " << QDir::toNativeSeparators(strfilename);pexceloperator->open(QDir::toNativeSeparators(strfilename));if(!pexceloperator->setSheet(1))
{QMessageBox::warning(this,QString(tr("错误")),QString(tr("读取文件失败!")));
}
else
{QMessageBox::information(NULL, "提示","成功读取文件", QMessageBox::Yes);
}QList<QList<QVariant> > listsheet;// 读取sheet1全部内容
this->pexceloperator->readAll(listsheet);QList< QList<QVariant> > listdatas;for(int iEquipmentPos = 0; iEquipmentPos < 10000; iEquipmentPos++)
{// 当前行内容QList<QVariant> listrows;for(unsigned int iPosRows = 0; iPosRows < 100; iPosRows++){// setCell(irowpos, 1, iEquipmentPos * iPosRows);listrows.append(iEquipmentPos * iPosRows);}// 将这行内容添加到列表listIDdatas.append(listrows);
}// 将所有内容写入到sheet文件
this->writeCurrentSheet(listdatas);// 保存并关闭工作表
pexceloperator->close();delete pexceloperator;
二、excelOperator.h
#ifndef EXCELOPERATOR_H
#define EXCELOPERATOR_H#include <QObject>
#include <ActiveQt/QAxObject>
#include <QDebug>
#include <QDir>
#include <QMap>
#include "equipment.h"class ExcelOperator : public QObject
{Q_OBJECT
public:explicit ExcelOperator(QObject *parent = nullptr);~ExcelOperator();//打开文件bool open(QString strpath);//关闭文件bool close();// 获取工作表数量int getSheetsCount();// 获取工作表路径QString getPath();// 根据名称创建工作表bool addSheet(QString strname);// 根据名称删除工作表bool delSheet(QString strname);//根据编号删除工作表bool delSheet(int iindex);// 根据名称设置工作表bool setSheet(QString strname);// 根据序号设置工作表bool setSheet(int iindex);//根据名称获取工作表QAxObject* getSheet(QString strname);//根据编号获取工作表QAxObject* getSheet(int iindex);//获取行对象QAxObject* getRows();//获取行数int getRowsCount();//获取列对象QAxObject* getColumns();//获取列数int getColumnsCount();//根据行列值获取单元格值, 如: 3行,5列QString getCell(int irow, int icolumn);//根据行列编号获取单元格值, 如: "F6"QString getCell(QString strnumber);//根据行列值设置单元格值bool setCell(int irow, int icolumn, QString strvalue);//根据行列编号设置单元格值bool setCell(QString strnumber, QString strvalue);// 一次读取sheet的全部内容void readAll(QList<QList<QVariant> > &res);// 一次写入sheet的全部内容bool writeCurrentSheet(const QList<QList<QVariant> > &cells);// 把QVariant转为QList<QList<QVariant>>void castVariant2ListListVariant(const QVariant &var, QList<QList<QVariant> > &res);// 把QList<QList<QVariant>>转为QVariantvoid castListListVariant2Variant(const QList<QList<QVariant> > &cells, QVariant &res);// 把列数转换为excel的字母列号void convertToColName(int idata, QString &res);// 数字转换为26字母QString to26AlphabetString(int idata);signals:public slots:
private:QAxObject*      m_pExcel;QAxObject*      m_pWorkbooks;QAxObject*      m_pWorkbook;QAxObject*      m_pWorksheets;QAxObject*      m_pWorksheet;QString         m_strPath;
};
#endif // EXCELOPERATOR_H
三、excelOperator.cpp
#include "exceloperator.h"
#include <objbase.h>
#include <QDebug>ExcelOperator::ExcelOperator(QObject *parent) : QObject(parent), m_pExcel(NULL), m_pWorkbooks(NULL), m_pWorkbook(NULL), m_pWorksheets(NULL), m_pWorksheet(NULL)
{m_pExcel = new(std::nothrow) QAxObject();m_pExcel->setControl("Excel.Application");m_pExcel->dynamicCall("SetVisible(bool)", false); // true 表示操作文件时可见,false表示为不可见m_pExcel->setProperty("DisplayAlerts", false); // 设置不显示任何警告信息m_pWorkbooks = m_pExcel->querySubObject("WorkBooks");
}ExcelOperator::~ExcelOperator()
{
//    close();m_pExcel->dynamicCall("Quit()");delete m_pExcel;m_pExcel = NULL;
}bool ExcelOperator::open(QString strpath)
{m_strPath = strpath;CoInitializeEx(NULL, COINIT_MULTITHREADED); // 为当前线程初始化COM库并设置并发模式if (NULL == m_pExcel){qCritical()<<"创建Excel对象失败...";return false;}try{// 按文件路径打开文件m_pWorkbook = m_pWorkbooks->querySubObject("Open(QString&)", m_strPath);// 获取打开的excel文件中所有的工作sheetm_pWorksheets = m_pWorkbook->querySubObject("WorkSheets");} catch (...){qCritical()<<"打开文件失败...";return false;}return true;
}bool ExcelOperator::close()
{qDebug()<<"excel close...";if (m_pExcel){qDebug()<<"closing...";QDir::toNativeSeparators(m_strPath));m_pWorkbook->dynamicCall("Save()");m_pWorkbook->dynamicCall("Close()");}return true;
}int ExcelOperator::getSheetsCount()
{int icount =  0;icount = m_pWorksheets->property("Count").toInt();return icount;
}QString ExcelOperator::getPath()
{return m_strPath;
}bool ExcelOperator::addSheet(QString strname)
{QAxObject *pWorkSheet = NULL;try{int icount = m_pWorksheets->property("Count").toInt();  //获取工作表数目QAxObject *pLastSheet = m_pWorksheets->querySubObject("Item(int)", icount);pWorkSheet = m_pWorksheets->querySubObject("Add(QVariant)", pLastSheet->asVariant());pLastSheet->dynamicCall("Move(QVariant)", pWorkSheet->asVariant());pWorkSheet->setProperty("Name", strname);  //设置工作表名称m_pWorkbook->dynamicCall("Save()");delete pWorkSheet;pWorkSheet = NULL;}catch (...){qCritical()<<"创建sheet失败...";return false;}if(pWorkSheet){delete pWorkSheet;pWorkSheet = NULL;}return true;
}bool ExcelOperator::delSheet(QString strname)
{try {QAxObject *pFirstSheet = m_pWorksheets->querySubObject("Item(QString)", strname);pFirstSheet->dynamicCall("delete");} catch (...) {qCritical()<<"删除sheet失败...";return false;}return true;
}bool ExcelOperator::delSheet(int iindex)
{try {QAxObject *pFirstSheet = m_pWorksheets->querySubObject("Item(int)", iindex);pFirstSheet->dynamicCall("delete");} catch (...) {qCritical()<<"删除sheet失败...";return false;}return true;
}bool ExcelOperator::setSheet(QString strname)
{try {m_pWorksheet = m_pWorksheet->querySubObject("Item(QString)", strname);} catch (...) {qCritical()<<"获取sheet失败...";return false;}return true;
}bool ExcelOperator::setSheet(int iindex)
{// 获取当前工作簿的表数量int isheetcounts = this->getSheetsCount();// 如果要设置的表不在当前工作簿的范围,则创建该表if(iindex > isheetcounts){QString strsheetname = "Sheet" + QString::number(iindex);if(!this->addSheet(strsheetname)){return false;}}try {m_pWorksheet = m_pWorksheets->querySubObject("Item(int)", iindex);} catch (...) {qCritical()<<"获取sheet失败...";return false;}return true;
}QAxObject* ExcelOperator::getSheet(QString strname)
{QAxObject* pWorkSheet = NULL;try {pWorkSheet = m_pWorksheets->querySubObject("Item(QString)", strname);} catch (...) {qCritical()<<"获取sheet失败...";}return pWorkSheet;
}QAxObject* ExcelOperator::getSheet(int iindex)
{QAxObject* pWorkSheet = NULL;try {pWorkSheet = m_pWorksheets->querySubObject("Item(int)", iindex);} catch (...) {qCritical()<<"获取sheet失败...";}return pWorkSheet;
}QAxObject* ExcelOperator::getRows()
{QAxObject* pRows = NULL;try {QAxObject* pUsedRange = m_pWorksheet->querySubObject("UsedRange");pRows = pUsedRange->querySubObject("Rows");} catch (...) {qCritical()<<"获取行失败...";}return pRows;
}int ExcelOperator::getRowsCount()
{int irows = 0;try {QAxObject* pUsedRange = m_pWorksheet->querySubObject("UsedRange");QAxObject* pRows = pUsedRange->querySubObject("Rows");irows = pRows->property("Count").toInt();} catch (...) {qCritical()<<"获取行数失败...";return 0;}return irows;
}QAxObject* ExcelOperator::getColumns()
{QAxObject* pColumns = NULL;try {QAxObject* pUsedRange = m_pWorksheet->querySubObject("UsedRange");pColumns = pUsedRange->querySubObject("Columns");} catch (...) {qCritical()<<"获取列失败...";}return pColumns;
}int ExcelOperator::getColumnsCount()
{int icolumns = 0;try {QAxObject* pUsedRange = m_pWorksheet->querySubObject("UsedRange");QAxObject* pColumns = pUsedRange->querySubObject("Columns");;icolumns = pColumns->property("Count").toInt();} catch (...) {qCritical()<<"获取列数失败...";return 0;}return icolumns;
}QString ExcelOperator::getCell(int iirow, int icolumn)
{QString strCell = "";try {QAxObject* pCell = m_pWorksheet->querySubObject("Cells(int, int)", iirow, icolumn);strCell = pCell->property("Value").toString();} catch (...) {qCritical()<<"获取单元格信息失败...";}return strCell;
}QString ExcelOperator::getCell(QString strnumber)
{QString strCell = "";try {QAxObject* pCell = m_pWorksheet->querySubObject("Range(QString)", strnumber);strCell = pCell->property("Value").toString();} catch (...) {qCritical()<<"获取单元格信息失败...";}return strCell;
}bool ExcelOperator::setCell(int irow, int icolumn, QString strvalue)
{try {QAxObject* pCell = m_pWorksheet->querySubObject("Cells(int, int)", irow, icolumn);pCell->setProperty("Value", strvalue);} catch (...) {qCritical()<<"写入单元格信息失败...";return false;}return true;
}bool ExcelOperator::setCell(QString strnumber, QString strvalue)
{try {QAxObject* pCell = m_pWorksheet->querySubObject("Range(QString)", strnumber);pCell->setProperty("Value", strvalue);} catch (...) {qCritical()<<"写入单元格信息失败...";return false;}return true;
}void ExcelOperator::readAll(QList<QList<QVariant> > &res)
{QVariant var;if (m_pWorksheet != NULL && ! m_pWorksheet->isNull()){// 获取该sheet的数据范围QAxObject * ax_usedRange = m_pWorksheet->querySubObject("UsedRange");if(NULL == ax_usedRange || ax_usedRange->isNull()){return;}// 获取该sheet的数据内容var = ax_usedRange->dynamicCall("Value");delete ax_usedRange;}this->castVariant2ListListVariant(var, res);return;
}bool ExcelOperator::writeCurrentSheet(const QList<QList<QVariant> > &cells)
{if(cells.size() <= 0)return false;if(NULL == this->m_pWorksheet || this->m_pWorksheet->isNull())return false;// 获取写入内容行数int irow = cells.size();// 获取写入内容列数int icol = cells.at(0).size();QString strRang;// 获取写入矩形内容最右边列标识this->convertToColName(icol, strRang);// 获取写入矩形内容最右边右下角单元格标识strRang += QString::number(irow);// 获取写入矩形内容写入范围strRang = "A2:" + strRang;qDebug()<< strRang;QAxObject *range = this->m_pWorksheet->querySubObject("Range(const QString&)", strRang);if(NULL == range || range->isNull()){return false;}bool succ = false;QVariant var;this->castListListVariant2Variant(cells, var);// 将数据写入到sheetsucc = range->setProperty("Value", var);delete range;return succ;
}void ExcelOperator::castVariant2ListListVariant(const QVariant &var, QList<QList<QVariant> > &res)
{QVariantList varRows = var.toList();if(varRows.isEmpty()){return;}const int rowCount = varRows.size();QVariantList rowData;for(int i=0;i<rowCount;++i){rowData = varRows[i].toList();res.push_back(rowData);}
}void ExcelOperator::castListListVariant2Variant(const QList<QList<QVariant> > &listcells, QVariant &varres)
{QVariantList vars;const int rows = listcells.size();for(int i = 0; i < rows; ++i){vars.append(QVariant(listcells[i]));}varres = QVariant(vars);
}void ExcelOperator::convertToColName(int idata, QString &strres)
{Q_ASSERT(idata > 0 && idata<65535);int tempData = idata / 26;if(tempData > 0){int mode = idata % 26;this->convertToColName(mode, strres);this->convertToColName(tempData, strres);}else{strres = (to26AlphabetString(idata)+ strres);}
}// 数字转换为26字母
QString ExcelOperator::to26AlphabetString(int idata)
{QChar ch = idata + 0x40; // A对应0x41return QString(ch);
}

QT 利用QAxObject大数据读写excel文件相关推荐

  1. POI3.8解决导出大数据量excel文件时内存溢出的问题

    POI3.8解决导出大数据量excel文件时内存溢出的问题 参考文章: (1)POI3.8解决导出大数据量excel文件时内存溢出的问题 (2)https://www.cnblogs.com/feng ...

  2. 对大数据量Excel文件自动排版、转换成PDF用于印刷出版

    excel排版大师 下载  http://pan.baidu.com/s/1eQnY0hW 2015.3. 目录 一.主要功能 2 二.系统需求 3 三.文件名要求 3 四.目录说明: 4 1.Exc ...

  3. Poi读取大数据量Excel文件

    前言 最近生产环境有个老项目一直内存报警,不时的还出现内存泄漏,导致需要重启服务器,已经严重影响正常服务了. 分析 1.dump内存文件 liunx使用如下命令: ? 1 ./jmap -dump:f ...

  4. Navicat premium 导入大数据的Excel文件失败的方法

    场景:有个Excel数据,有20W行数据,是xlsx格式的,想要使用 Navicat premium 直接导入到mysql中,但是,导入完成后只导入了3000多条,且没有提示导入错误. [解决方法] ...

  5. 大数据量Excel Import导致OOM问题

    http://www.iteye.com/topic/199061 正在做一个Excel import的东东,不知道论坛上用POI的朋友有没有考虑过大数据量Excel文件导入导致内存溢出的问题 HSS ...

  6. R读写Excel文件中数据的方法

    用R语言读写Excel的方法有很多,但每种方法都有让人头疼的地方,比如xlsx包的代码复杂,只支持Excel2007:RODBC不易理解,限制太多,程序不稳定,会出各种怪毛病.另存为csv格式的方法倒 ...

  7. java读写excel文件poi_Java利用POI读写Excel文件工具类

    本文实例为大家分享了Java读写Excel文件工具类的具体代码,供大家参考,具体内容如下 package com.test.app.utils; import java.io.File; import ...

  8. excel python插件_利用 Python 插件 xlwings 读写 Excel

    Python 通过 xlwings 读取 Excel 数据 去年底公司让我做设备管理,多次委婉拒绝,最终还是做了.其实我比较喜欢技术.做管理后发现现场没有停机率统计,而原始数据有,每次要自己在Exce ...

  9. c# 中wpfexcel_VS2017下编写C#程序读写Excel文件

    原标题:VS2017下编写C#程序读写Excel文件 前言: 有时候我们需要对Excel文件进行特殊处理,这种情况下写个小程序是很方便的.最近刚开始学C#,正好有同学需要处理个Excel文件,我就写了 ...

最新文章

  1. 《嵌入式 Linux应用程序开发标准教程(第2版)》——1.1 嵌入式Linux基础
  2. rockMongo时区警告的解决
  3. (35)3环PEB断链
  4. python正则判断列表是否有元素,python – 从列表中删除正则表达式元素
  5. php 新浪url,PHP URL函数详解
  6. 万字长文:近年来学界、业界视角下的“事理图谱”发展总结与思考
  7. 掌握基本的Java程序开发过程 题库 1213
  8. 变电所自动化系统的电源配置
  9. 云南大学计算机调剂哪个方向比较容易,选择考研调剂,看准这几大调剂方向!...
  10. MySQL · BUG分析 · Rename table 死锁分析
  11. 小米wifi驱动 linux驱动,小米wifi驱动程序
  12. 水经注下载的地图版权_怎么下载天地图地方高清影像
  13. Javaweb-学习路线
  14. 【整理】关于Android图形系统的一些事实真相
  15. React+ant中的Form表单的刷新
  16. 【渝粤题库】广东开放大学 建筑力学与结构 形成性考核
  17. C++有关类的基本函数总结
  18. EditPlus安装Json格式化工具功能
  19. ConstraintLayout中Chains和Guideline的使用
  20. 石家庄阿福卡4G问题

热门文章

  1. 基本磁盘与所谓动态磁盘区别
  2. 时分秒表达式java_java 时分秒正则表达式
  3. 两因素身份验证增强您的Spring Security
  4. canvas教程14-资源管理器
  5. org.apache.flink.shaded.guava18.com.google.common.util.concurrent.ThreadFactoryBuilder 真实解决方案
  6. 程序人生 - 2020年杭州市积分入学实施办法权威解读
  7. 【C语言】计算个位十位百位思路
  8. leetcode 1276. 不浪费原料的汉堡制作方案(C++)
  9. github项目的JAVA项目Ratel,基于Netty实现
  10. 将手机、平板变成电脑第二屏