QT 利用QAxObject大数据读写excel文件
作者:互联网
不知不觉已经加入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);
// 将数据写入到sheet
succ = 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对应0x41
return 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>>转为QVariant
void 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文件中所有的工作sheet
m_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);
// 将数据写入到sheet
succ = 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对应0x41
return QString(ch);
}
标签:ExcelOperator,QT,int,querySubObject,excel,QAxObject,QString,QVariant 来源: https://blog.csdn.net/diaonimagebikao/article/details/110672058