Qt 快速读写Excel指南

2023-10-26

Qt Windows 下快速读写Excel指南

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

读取excel慢的原因

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

 1 QVariant ExcelBase::read(int row, int col)
 2 {
 3     QVariant ret;
 4     if (this->sheet != NULL && ! this->sheet->isNull())
 5     {
 6         QAxObject* range = this->sheet->querySubObject("Cells(int, int)", row, col);
 7         //ret = range->property("Value");
 8         ret = range->dynamicCall("Value()");
 9         delete range;
10     }
11     return ret;
12 }

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

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

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

快速读取excel文件

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

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

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

 1 QVariant ExcelBase::readAll()
 2 {
 3     QVariant var;
 4     if (this->sheet != NULL && ! this->sheet->isNull())
 5     {
 6         QAxObject *usedRange = this->sheet->querySubObject("UsedRange");
 7         if(NULL == usedRange || usedRange->isNull())
 8         {
 9             return var;
10         }
11         var = usedRange->dynamicCall("Value");
12         delete usedRange;
13     }
14     return var;
15 }

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

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

 1 ///
 2 /// \brief 把QVariant转为QList<QList<QVariant> >
 3 /// \param var
 4 /// \param res
 5 ///
 6 void ExcelBase::castVariant2ListListVariant(const QVariant &var, QList<QList<QVariant> > &res)
 7 {
 8     QVariantList varRows = var.toList();
 9     if(varRows.isEmpty())
10     {
11         return;
12     }
13     const int rowCount = varRows.size();
14     QVariantList rowData;
15     for(int i=0;i<rowCount;++i)
16     {
17         rowData = varRows[i].toList();
18         res.push_back(rowData);
19     }
20 }

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

对于如下如的excel:

 读取后的QList<QList<QVariant> >结构如下所示:

 

继续展开

 

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

 1 void MainWindow::on_action_open_triggered()
 2 {
 3     QString xlsFile = QFileDialog::getOpenFileName(this,QString(),QString(),"excel(*.xls *.xlsx)");
 4     if(xlsFile.isEmpty())
 5         return;
 6     QElapsedTimer timer;
 7     timer.start();
 8     if(m_xls.isNull())
 9         m_xls.reset(new ExcelBase);
10     m_xls->open(xlsFile);
11     qDebug()<<"open cost:"<<timer.elapsed()<<"ms";timer.restart();
12     m_xls->setCurrentSheet(1);
13     m_xls->readAll(m_datas);
14     qDebug()<<"read data cost:"<<timer.elapsed()<<"ms";timer.restart();
15     QVariantListListModel* md = qobject_cast<QVariantListListModel*>(ui->tableView->model());
16     if(md)
17     {
18         md->updateData();
19     }
20     qDebug()<<"show data cost:"<<timer.elapsed()<<"ms";timer.restart();
21 }

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

1 QScopedPointer<ExcelBase> m_xls;
2 QList< QList<QVariant> > m_datas;

读取的耗时:

1 "D:\czy_blog\czyBlog\04_fastReadExcel\src\fastReadExcelInWindows\excelRWByCztr1988.xls"
2 open cost: 1183 ms
3 read data cost: 229 ms
4 show data cost: 14 ms

10万个也就0.2秒而已

快速写入excel文件

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

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

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

 1 ///
 2 /// \brief 写入一个表格内容
 3 /// \param cells
 4 /// \return 成功写入返回true
 5 /// \see readAllSheet
 6 ///
 7 bool ExcelBase::writeCurrentSheet(const QList<QList<QVariant> > &cells)
 8 {
 9     if(cells.size() <= 0)
10         return false;
11     if(NULL == this->sheet || this->sheet->isNull())
12         return false;
13     int row = cells.size();
14     int col = cells.at(0).size();
15     QString rangStr;
16     convertToColName(col,rangStr);
17     rangStr += QString::number(row);
18     rangStr = "A1:" + rangStr;
19     qDebug()<<rangStr;
20     QAxObject *range = this->sheet->querySubObject("Range(const QString&)",rangStr);
21     if(NULL == range || range->isNull())
22     {
23         return false;
24     }
25     bool succ = false;
26     QVariant var;
27     castListListVariant2Variant(cells,var);
28     succ = range->setProperty("Value", var);
29     delete range;
30     return succ;
31 }

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

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

 1 ///
 2 /// \brief 把列数转换为excel的字母列号
 3 /// \param data 大于0的数
 4 /// \return 字母列号,如1->A 26->Z 27 AA
 5 ///
 6 void ExcelBase::convertToColName(int data, QString &res)
 7 {
 8     Q_ASSERT(data>0 && data<65535);
 9     int tempData = data / 26;
10     if(tempData > 0)
11     {
12         int mode = data % 26;
13         convertToColName(mode,res);
14         convertToColName(tempData,res);
15     }
16     else
17     {
18         res=(to26AlphabetString(data)+res);
19     }
20 }
21 ///
22 /// \brief 数字转换为26字母
23 ///
24 /// 1->A 26->Z
25 /// \param data
26 /// \return
27 ///
28 QString ExcelBase::to26AlphabetString(int data)
29 {
30     QChar ch = data + 0x40;//A对应0x41
31     return QString(ch);
32 }

看看写excel的耗时:

 1 void MainWindow::on_action_write_triggered()
 2 {
 3     QString xlsFile = QFileDialog::getExistingDirectory(this);
 4     if(xlsFile.isEmpty())
 5         return;
 6     xlsFile += "/excelRWByCztr1988.xls";
 7     QElapsedTimer timer;
 8     timer.start();
 9     if(m_xls.isNull())
10         m_xls.reset(new ExcelBase);
11     m_xls->create(xlsFile);
12     qDebug()<<"create cost:"<<timer.elapsed()<<"ms";timer.restart();
13     QList< QList<QVariant> > m_datas;
14     for(int i=0;i<1000;++i)
15     {
16         QList<QVariant> rows;
17         for(int j=0;j<100;++j)
18         {
19             rows.append(i*j);
20         }
21         m_datas.append(rows);
22     }
23     m_xls->setCurrentSheet(1);
24     timer.restart();
25     m_xls->writeCurrentSheet(m_datas);
26     qDebug()<<"write cost:"<<timer.elapsed()<<"ms";timer.restart();
27     m_xls->save();
28 }

输出:

1 create cost: 814 ms 
2 "A1:CV1000" 
3 write cost: 262 ms 

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

结论

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

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt 快速读写Excel指南 的相关文章

  • 如何访问Loader的sourceComponent中的QML对象?

    我可能需要读取或写入的一些属性Loader s sourceComponent来自一些外部函数 访问该房产的方式是什么x里面的对象的Loader s sourceComponent import QtQuick 2 0 Item width
  • 是否存在用于开放 xml Excel 编辑的良好包装类和/或库?

    我正在寻找一个不错的库 用于在我们的 Windows 服务器上编辑和 或生成 Excel 文档 我觉得 open xml sdk 可能是可行的方法 但对我来说 学习曲线似乎很陡峭 而且我们的开发时间有限 我认为编辑 Excel 文档不应该那
  • 将 Excel 文件读入 R 并锁定单元格

    我有一个 Excel 电子表格要读入 R 它受密码保护并锁定了单元格 我可以使用 excel link 导入受密码保护的文件 但我不知道如何解锁 取消保护单元格 excel link 给了我这个错误 gt
  • VBA (Excel) 中 =Empty 和 IsEmpty() 有什么区别?

    我使用了以下 VBA 代码 Do While Cell i 1 lt gt Empty doing things i i 1 Loop 在 Excel 中迭代列 具有双精度 整数值 然后我发现了一种情况 每当单元格的值为 0 时 测试的计算
  • 如何隐藏组合框下拉列表中的列?

    我正在 Excel 用户窗体中构建一个 ComboBox 该用户窗体从 Access 表中获取其行 我想在下拉列表中向用户显示多个文本字段 但从 ComboBox 返回的值应该是与用户选择的行关联的 ID 号 即 ID 列是绑定列 但我不想
  • 在 Qthread 中运行函数 - 应用程序将挂起

    我在 QT 内部线程方面遇到一些问题 include
  • 在用户窗体终止/关闭 VBA 时调用数组

    我有一个问题 我想在用户窗体关闭时将用户窗体的内容存储在数组中 我认为我的语法正确 但似乎不会在用户窗体初始化时重新填充 我尝试将数组放入其自己的模块中 但这也不起作用 有人愿意启发我吗 示例代码 Public Sub DPArrayStu
  • 使用 python 中的公式函数使从 Excel 中提取的值的百分比相等

    import xlrd numpy excel Users Bob Desktop wb1 xlrd open workbook excel assignment3 xlsx sh1 wb1 sheet by index 0 colA co
  • 使用 Python Pandas 获取多个值来制作表格

    使用我的代码 我可以将两个 Excel 数据库连接到 1 中 问题是它只显示收入列 而不显示列展示次数 为了更清楚 我留下了代码和示例 我尝试过 df1 df1 pivot index Cliente columns Fecha value
  • 如何使用Excel的墨迹工具添加手写签名?

    我想在我公司的一些表格中添加手写数字签名 目标是选择一个文档 添加签名 通过使用绘图板 这可以使用 Excel 的墨水工具完成 并将文件作为 PDF 存储在服务器中 这将消除打印然后扫描表格以获得签名的必要性 我使用 Excel 作为文件操
  • 从 Excel VBA 调用 Bloomberg BQL 查询

    出于复杂的原因 我想在 VBA 中自动调用 Bloomi BQL 查询 我正在从 VBA 脚本更改 Excel 工作表中 BQL Query 公式的输入 并调用 Application Calculate 来运行查询 显示更改为 N A 请
  • 在 BIRT 中导出的 Excel 中表格单元格的文本换行

    我在 eclipse 中使用 BIRT 4 4 1 来生成报告 我想包装表头的文本 它在网络查看器中工作正常 但是当我导出到 Excel 时 表单元格文本在一行中 并且文本也溢出 我不想使单元格宽度等于内容 我想根据其容器宽度来换行文本 我
  • 如何使用 VBA 将行从一张 Excel 工作表复制到另一张 Excel 工作表并创建重复项?

    我有一个包含两张表的 Excel 工作簿 sheet1 在 A 到 R 列中包含一个大型数据表 标题位于第 1 行 Sheet2 在 A 到 AO 列中包含数据 我试图使用 VBA 从sheet1 复制行并将它们粘贴到sheet2 的末尾
  • Qt:删除富文本

    对于明文有QFontMetrics elideText https doc qt io qt 5 qfontmetrics html elidedText https doc qt io qt 5 qfontmetrics html eli
  • 使用嵌入qt的mysql?

    我正在尝试使用嵌入 QT 的 mysql 我已经有一个与 mysqld 链接的 Qt mysql 插件 该插件可以很好地加载嵌入式数据库 但 QT 没有简单的方法来设置 dataDir 等嵌入式选项 我在这里看到 http doc qt i
  • 从 excel/vba 生成电子邮件到 Outlook 时,我的电子邮件签名不会出现?

    您好 我使用 Ron De Bruin 的精彩网站创建了 VBA 代码 该代码可以从 Excel 文件生成向特定用户发送的电子邮件 唯一的问题是我的签名没有出现在每封电子邮件上 而且我似乎找不到如何在代码中添加它 有人可以建议吗 正如你所知
  • 面向 Delphi 开发人员的 Qt

    有人知道为 Delphi C Builder VCL 开发人员解释 Qt 的书籍或教程吗 对于具有该背景的开发人员来说 学习 Qt 的最佳方法是什么 我对如何使用 Qt 完成我知道如何在 Delphi 中完成的事情特别感兴趣 例如 Qt 相
  • 在 Nodejs/javascript 中的 Excel 中创建动态数量的列或标题

    我用过exceljsNodejs中用于将json数据导出到excel的模块 它工作正常 但必须在添加行之前预定义标题 列的名称 即列是固定的 添加行后 我无法动态添加列 我尝试了许多通过 npm 提供的模块 但它们都具有相同的功能 那么 有
  • 调用 UDF 时公式中使用的值的数据类型错误

    我一直在努力找出这里出了什么问题 我有两个包含字符串值的列 我使用第三列调用工作表中的 UDF 但最终得到 Value 并出现错误 公式中使用的值的数据类型错误 Eg Col I Col J File1 Y File1 N File2 Y
  • wkhtmltopdf 修补了 qt 吗?

    我正在尝试将多个 URL 转换为 PDF 但是 当我编译 wkhtmltopdf 或运行时apt get install wkhtmltopdf并尝试一下 它说 错误 此版本的 wkhtmltopdf 是针对未修补的 QT 版本构建的 并且

随机推荐

  • ESXI虚拟机厚置备延迟置零转换为Thin Provision方法

    最近有博友提出一个需求 他们公司的服务器磁盘空间不足了 现在无法正常创建虚拟机 其实并没有使用到这么多空间 只是因为划了这么多空间给虚拟机 所以造成磁盘空间不足 那么是否有什么解决的方法了 详细了解发现虚拟机在配置磁盘的时候设置的是厚置备延
  • RC低通滤波器

    先来几个不错的资源链接 1 RC滤波器截止频率在线计算器 http www eechina com tools rc filter cutoff frequency html 2 详谈一阶RC低通滤波器如何过滤高频噪声 网上不错的一个帖子
  • Linux学习-43-挂载Linux系统外的文件mount和卸载文件系统umount命令用法

    10 10 mount命令详解 挂载Linux系统外的文件 所有的硬件设备必须挂载之后才能使用 新硬盘先格式化后创建分区 再对分区进行挂载 只不过 有些硬件设备 比如硬盘分区 在每次系统启动时会自动挂载 而有些 比如 U 盘 光盘 则需要手
  • 使用w,vmstat命令,top命令,sar命令,nload命令

    监控系统状态 w命令 uptime load average 0 00 0 01 0 05 上面这条显示的就是系统负载 后面有三段数字 root localhost w 21 33 04 up 41 min 1 user load aver
  • STS & 开发异常

    1 Failed to start component 情景 本地 tomcat 部署了两个项目 一个provider 一个 server 前台通过server访问 provider 在开发的时候 将tomcat部署的服务 Clean 或者
  • Android-模块化-项目实践和探索分享

    文章目录 前言 一 gradle统一配置 1 多模块项目的构建 2 根项目的构建配置 3 常用公用的构建配置 二 nexus与maven publish 1 安装nexus 2 仓库 3 maven publish 三 动态依赖 1 依赖的
  • 在IDEA中使用Maven将项目打包成jar包

    1 在pom xml文件中添加代码
  • [Python图像处理] 二十九.MoviePy视频编辑库实现抖音短视频剪切合并操作

    该系列文章是讲解Python OpenCV图像处理知识 前期主要讲解图像入门 OpenCV基础用法 中期讲解图像处理的各种算法 包括图像锐化算子 图像增强技术 图像分割等 后期结合深度学习研究图像识别 图像分类应用 希望文章对您有所帮助 如
  • 【质量】代码质量评价标准

    今天来思考下如何评价代码质量 业界公认比较认可的七大标准 可维护性 maintainability 可读性 readability 可扩展性 extensibility 灵活性 flexibility 简洁性 simplicity 可复用性
  • ReentrantReadWriteLock

    一ReentrantReadWriteLock 是Lock的另一种实现方式 我们知道ReentrantLock是一个排他锁 同一时间只允许一个线程访问 而ReentrantReadWriteLock允许多个读线程同时访问 但不允许写线程和读
  • RuntimeError: Address already in use

    Pytorch用多张GPU训练时 会报地址已被占用的错误 其实是端口号冲突了 因此解决方法要么kill原来的进程 要么修改端口号 在代码里重新配置 torch distributed init process group dist init
  • ajax异步加载jqgrid之动态创建

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 之前写过一篇过于ajax异步加载jqgrid的文章 那个只是一个特殊的情况 如果创建不同数据库表的jqgrid 必须分别写servlet dao层和连接池 很麻烦 今天我写
  • Hive insert overwrite 问题

    微信公众号 苏言论 理论联系实际 畅言技术与生活 文章目录 1 测试的版本 2 insert overwrite使用说明 3 示例 4 建议的操作 5 参考链接 1 测试的版本 Apache hive 1 1 0 2 3 1 3 1 0 2
  • vue3 全局批量注册组件

    思路 1 使用 require 提供的函数 context 加载某一个目录下的所有 vue 后缀的文件 2 context 函数会返回一个导入函数 importFn 3 它有一个方法 keys 获取所有的文件路径 4 通过文件路径数组 通过
  • Ubuntu20.04 + 3090 安装nvidia驱动,附加解决重启黑屏卡在 /dev/***: clean, **files,***blocks的问题

    目录 准备 禁用nouveau 解决黑屏问题并安装驱动 参考 准备 首先需要知道当前电脑 服务器的显卡型号 这个自行查找自己电脑配置 查找显卡对应的驱动版本 通过命令ubuntu drivers devices查看当前设备所支持的驱动 带有
  • Android 监控SD卡的插拔状态

    http blog csdn net pasterzhang article details 8151877 我们是以DV6300 T的平台来做测试的 发现有2种方式来检测Android中external media 包括SD卡 USB 的
  • Spring Cloud Feign nested exception is java.lang.IllegalStateException

    Spring Cloud Feign 使用时抛出异常 nested exception is java lang IllegalStateException RequestParam value was empty on parameter
  • 数据结构——广度优先遍历(队列)

    队列的基本操作 include
  • 单片机C语言零基础入门05 - 逻辑运算

    硬件家园单片机C语言零基础入门资料汇总链接 https mp weixin qq com s hMTreNUX V90461tvALjJA 一 逻辑与或非 基础理论 逻辑与或非 运算对象是布尔值 1或0 真或假 类似于数字电路的与门 或门
  • Qt 快速读写Excel指南

    Qt Windows 下快速读写Excel指南 很多人搜如何读写excel都会看到用QAxObject来进行操作 很多人试了之后都会发现一个问题 就是慢 非常缓慢 因此很多人得出结论是QAxObject读写excel方法不可取 效率低 后来