Qt快速读取Excel并用Eigen对数据进行矩阵运算处理
前言
这个是做matlab移植C++时的一个子程序,为的是利用Eigen库使matlab程序移植过程更加平滑,可以调用Eigen库丰富强大的功能进行矩阵运算,前后也解决了不少问题(主要是一些使用方法的错误 ,hhh),现在读表速度还可以,十万数据量左右的表格读取加存储大概3ms。
应该还能优化,比如读取后直接转矩阵而不是逐个读入,蹲评论区dalao
Qt快速读取Excel数据
使用QAxObject存储Excel对象内容
要想打开Excel对应接口,Qt要在编译文件里头加上axcontainer,写法详见Qt的 “.pro” 文件写法
QT += core gui
CONFIG += axcontainer
QT += axcontainer
然后可以用QAxObject存储Excel对象内容
头文件
QAxObject* excel; //操作Excel文件对象(open-save-close-quit)
QAxObject* workbooks; //总工作薄对象
QAxObject* workbook; //操作当前工作薄对象
QAxObject* worksheets; //文件中所有<Sheet>表页 QAxObject* worksheet; //存储第n个sheet对象
QAxObject* usedrange; //存储当前sheet的数据对象
QAxObject* pWorkBooks;
QVariant qvar;
.cpp
ExcelRead::ExcelRead()
{
excel = NULL; //在构造函数中进行初始化操作
workbooks = NULL;
workbook = NULL;
worksheets = NULL;
worksheet = NULL;
usedrange = NULL;
//pWorkBooks = NULL;
}
bool ExcelRead::datarange_init(QString &filename, int& totalRow, int& totalCol)
{
excel = new QAxObject("Excel.Application"); //创建Excel对象连接驱动
excel->dynamicCall("SetVisible(bool)",false); //ture的打开Excel表 false不打开Excel表
excel->setProperty("DisplayAlerts",false);
workbooks = excel->querySubObject("WorkBooks");
workbook = workbooks->querySubObject("Open(const QString&)",filename); //打开指定Excel
worksheets = workbook->querySubObject("WorkSheets"); //获取表页对象
worksheet = worksheets->querySubObject("Item(int)",1); //获取第1个sheet表
usedrange = worksheet->querySubObject("Usedrange"); //获取权限
iRow = usedrange->property("Row").toInt(); //数据起始行数和列数(可以解决不规则Excel)
iCol = usedrange->property("Column").toInt();
//cout<<"start_row= "<<iRow<<"\t start_col="<<iCol<<endl;
totalRow = usedrange->querySubObject("Rows")->property("Count").toInt(); //获取数据总行数
totalCol = usedrange->querySubObject("Columns")->property("Count").toInt();
//
//qvar = usedrange->dynamicCall("Value");
qvar = usedrange->dynamicCall("Value2");
delete usedrange;
//pWorkBooks->dynamicCall("Close(Boolean)",false);
excel->dynamicCall("Quit(void)");
delete excel;
return true;
}
querySubObject调用一次就足够,反复调用会导致内存堆积读取速度大幅降低。
excel对象在打开后要记得退出,如果不退出,该excel文档后台会一直显示为占用状态
excel->dynamicCall("Quit(void)");
数据格式转换
主要是用 QVar -> Qlist -> float
void ExcelRead::Var2Qlist(QVariant var, QList<QList<QVariant> > &qlist)
{
QVariantList varRows = var.toList();
const int rowCount = varRows.size();
QVariantList rowData;
for(int i=0;i<rowCount;++i)
{
rowData = varRows[i].toList();
qlist.push_back(rowData);
}
}
QVarient转换部分参考了其他开发者的博客
在Qlist基础上用 “.toFloat ” 转换为float型可处理数据
bool ExcelRead::readExcelData(QString& filename,MatrixXf& m) //读了全表数据
{
if(datarange_init(filename,totalrow,totalcol))
cout<<"excel_init successed !"<<endl;
m = MatrixXf::Zero(totalrow,totalcol);
QList<QList<QVariant> > vec;
// QElapsedTimer timer;
// timer.start();
QTime startTime = QTime::currentTime();
// 逐行读取主表
Var2Qlist(qvar,vec);
for (int i = iRow+1; i <= totalrow; i++){
for(int j = iCol; j <= totalcol; j++){
//m(i-1,j-1) = worksheet->querySubObject("Cells(int,int)",i,j)->dynamicCall(("Value2()")).value<float>();
m(i-1,j-1) = vec[i-1][j-1].toFloat();
}
}
QTime stopTime = QTime::currentTime();
int elapsed = startTime.msecsTo(stopTime);
//qDebug()<<filename<<" data has been put in Matrix, it took: "<<timer.elapsed()<<"ms";
qDebug()<<filename<<" data has been put in Matrix, it took: "<<elapsed<<"ms";
qvar.clear();
// vec.clear();
//cout << m.rows()<<endl;
return true;
}
后记
十分感谢csdn和github上丰富的资源,在解决问题时借鉴和学习到了很多。
这里附上小项目源码:
https://github.com/mhw-Parker/Qt_FastReadExcel.git
欢迎评论区提出更高效读取方案。