Windows Qt5下用QAxObject快速读写Excel指南

时间:2024-05-21 09:10:48

Qt Windows 下快速读写Excel指南

很多人搜如何读写excel都会看到用QAxObject来进行操作,很多人试了之后都会发现一个问题,就是慢,非常缓慢!因此很多人得出结论是QAxObject读写excel方法不可取,效率低。 
后来我曾试过用ODBC等数据库类型的接口进行读写,遇到中文嗝屁不说,超大的excel还是会读取速度慢。 
最后,看了一些开源的代码后发现,Windows下读取excel,还是用QAxObject最快!没错,就是用QAxObject读写最快!!!(读取10万单元格229ms) 
大家以后读取excel时(win下),不用考虑别的方法,用QAxObject就行,速度杠杠的,慢是你操作有误!下面就说说如何能提高其读取效率。

读取excel慢的原因

这里不说如何打开或生成excel,着重说说如何快速读取excel。 
网上搜到用Qt操作excel的方法,读取都是使用类似下面这种方法进行:

Windows Qt5下用QAxObject快速读写Excel指南

读取慢的根源就在于sheet->querySubObject("Cells(int, int)", row, col)

试想有10000个单元就得调用10000次querySubObject,网络上90%的教程都没说这个querySubObject产生的QAxObject*最好进行手动删除,虽然在它的父级QAxObject会管理它的内存,但父级不析构,子对象也不会析构,若调用10000次,就会产生10000个QAxObject对象 
得益于QT快速读取数据量很大的Excel文件此文,下面总结如何快速读写excel

快速读取excel文件

原则是一次调用querySubObject把所有数据读取到内存中 
VBA中可以使用UsedRange把所有用到的单元格范围返回,并使用属性Value把这些单元格的所有值获取。

这时,获取到的值是一个table,但Qt把它变为一个变量QVariant来储存,其实实际是一个QList<QList<QVariant> >,此时要操作里面的内容,需要把这个QVariant转换为QList<QList<QVariant> >

先看看获取整个单元格的函数示意(这里ExcelBase是一个读写excel的类封装):

Windows Qt5下用QAxObject快速读写Excel指南

代码中this->sheet是已经打开的一个sheet,再获取内容时使用this->sheet->querySubObject("UsedRange");即可把所有范围都获取。

下面这个castVariant2ListListVariant函数把QVariant转换为QList<QList<QVariant> >

这样excel的所有内容都转换为QList<QList<QVariant>>保存,其中QList<QList<QVariant> >QList<QVariant>为每行的内容,行按顺序放入最外围的QList中。

对于如下如的excel:

Windows Qt5下用QAxObject快速读写Excel指南

Windows Qt5下用QAxObject快速读写Excel指南

Windows Qt5下用QAxObject快速读写Excel指南

下面看看此excel的读取速度有多高 
这里有个excel,有1000行,100列,共计十万单元格,打开使用了一些时间,读取10万单元格耗时229毫秒, 
读取的代码如下:(完整源代码见后面)

Windows Qt5下用QAxObject快速读写Excel指南

上面的m_xls和m_datas是成员变量:

Windows Qt5下用QAxObject快速读写Excel指南

读取的耗时:

Windows Qt5下用QAxObject快速读写Excel指南

10万个也就0.2秒而已

快速写入excel文件

同理,能通过QAxObject *usedRange = this->sheet->querySubObject("UsedRange");实现快速读取,也可以实现快速写入

快速写入前需要些获取写入单元格的范围:Range(const QString&) 
如excel的A1为第一行第一列,那么A1:B2就是从第一行第一列到第二行第二列的范围。

要写入这个范围,同样也是通过一个与之对应的QList<QList<QVariant> >,具体见下面代码:

Windows Qt5下用QAxObject快速读写Excel指南

Windows Qt5下用QAxObject快速读写Excel指南

此函数是把数据从A1开始写

函数中的convertToColName为把列数,转换为excel中用字母表示的列数,这个函数是用递归来实现的:

Windows Qt5下用QAxObject快速读写Excel指南

Windows Qt5下用QAxObject快速读写Excel指南

看看写excel的耗时:

Windows Qt5下用QAxObject快速读写Excel指南

Windows Qt5下用QAxObject快速读写Excel指南

Windows Qt5下用QAxObject快速读写Excel指南

写10万个数据耗时262ms,有木有感觉很快,很强大

结论

  • Qt在windows下读写excel最快速的方法还是使用QAxObject
  • 不要使用类似sheet->querySubObject("Cells(int, int)", row, col);的方式读写excel,这是导致低效的更本原因

源代码

Windows Qt5下用QAxObject快速读写Excel指南

–> 见 github