一、前言

做数据导出,少量的数据比如10W级别以下的,基本上直接占用主线程也是很快的就可以处理完,上了百万级别的数据量以后,就会发现性能极速下降,很容易卡主整体界面,于是这部分处理必须要用到线程,本数据导出到xls组件采用xml格式的数据,固定的头部和尾部数据,中间是一行行的数据,于是需要把这部分移到线程执行,用户主动初始化类以后调用open方法打开文件,并先输出好头部数据,然后开启线程,调用append方法逐行输出数据,百万千万级别也可以慢慢输出,线程排队输出到文件,最后用户主动调用close关闭文件,输出尾部数据,形成最终的文件。

数据导出到xls基本步骤:

  • 打开文件,采用QTextStream输出数据到文件。
  • 输出固定头部信息。
  • 输出文档信息。
  • 输出边框样式。
  • 输出表结构。
  • 输出字段名称。
  • 逐行输出数据。
  • 输出固定尾部信息。

二、功能特点

  1. 组件同时集成了导出数据到csv、xls、pdf和打印数据。
  2. 所有操作全部提供静态方法无需new,数据和属性等各种参数设置采用结构体数据,极为方便。
  3. 同时支持QTableView、QTableWidget、QStandardItemModel、QSqlTableModel等数据源。
  4. 提供静态方法直接传入QTableView、QTableWidget控件,自动识别列名、列宽和数据内容。
  5. 每组功能都提供单独的完整的示例,注释详细,非常适合各阶段Qter程序员。
  6. 原创导出数据机制,不依赖任何office组件或者操作系统等第三方库,支持嵌入式linux。
  7. 速度超快,9个字段10万行数据只需要2秒钟完成。
  8. 只需要四个步骤即可开始急速导出海量数据比如100W条记录到Excel。
  9. 同时提供直接写入数据接口和多线程写入数据接口,不卡主界面。
  10. 可设置标题、副标题、表名。
  11. 可设置导出数据的字段名、列名、列宽。
  12. 可设置末尾列自动拉伸填充,默认拉伸更美观。
  13. 可设置是否启用校验过滤数据,启用后符合规则的数据特殊颜色显示。
  14. 可指定校验的列、校验规则、校验值、校验值数据类型。
  15. 校验规则支持 精确等于==、大于>、大于等于>=、小于<、小于等于<=、不等于!=、包含contains。
  16. 校验值数据类型支持 整型int、浮点型float、双精度型double,默认文本字符串类型。
  17. 可设置随机背景颜色及需要随机背景色的列集合。
  18. 支持分组输出数据,比如按照设备分组输出数据,方便查看。
  19. 可设置csv分隔符、行内容分隔符、子内容分隔符。
  20. 可设置边框宽度、自动填数据类型,默认自动数据类型开启。
  21. 可设置是否开启数据单元格样式,默认不开启,不开启可以节约大概30%的文件体积。
  22. 可设置横向排版、纸张边距等,比如导出到pdf以及打印数据。
  23. 支持图文混排导出数据到pdf以及打印数据,自动分页。
  24. 灵活性超高,可自由更改源码设置对齐方式、文字颜色、背景颜色等。
  25. 支持任意excel表格软件,包括但不限于excel2003-2021、wps、openoffice等。
  26. 纯Qt编写,支持任意Qt版本+任意编译器+任意系统。

三、体验地址

  1. 体验地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 文件名:bin_dataout.zip
  2. 国内站点:https://gitee.com/feiyangqingyun
  3. 国际站点:https://github.com/feiyangqingyun
  4. 个人主页:https://blog.csdn.net/feiyangqingyun
  5. 知乎主页:https://www.zhihu.com/people/feiyangqingyun/

四、效果图

五、相关代码

void frmDataThread::append()
{
//先判断是否已经输出完成数据
if (currentCount >= AppConfig::RowThread) {
QString info;
if (AppConfig::TypeThread == 0) {
info = QString("%1 输出完成 (共 %2 条/总计 %3 条) 用时 %4 秒").arg(TIMEMS)
.arg(AppConfig::RowThread).arg(AppConfig::RowThread).arg(xls->getUseTime());
xls->stop();
xls->close();
} else {
info = QString("%1 输出完成 (共 %2 条/总计 %3 条) 用时 %4 秒").arg(TIMEMS)
.arg(AppConfig::RowThread).arg(AppConfig::RowThread).arg(pdf->getUseTime());
pdf->stop();
} ui->textEdit->setTextColor("#A279C5");
ui->textEdit->append(info);
ui->btnStart->setEnabled(true);
ui->progressBar->setValue(ui->progressBar->maximum()); return;
} QElapsedTimer time;
time.start(); for (int i = 0; i < AppConfig::CountThread; i++) {
QStringList list;
for (int j = 0; j < AppConfig::ColumnThread; j++) {
list << QString("%1_%2").arg(i + 1).arg(j + 1);
} if (AppConfig::TypeThread == 0) {
xls->append(list.join(";"));
} else {
pdf->append(list.join(";"));
}
} currentCount += AppConfig::CountThread;
ui->progressBar->setValue(currentCount);
QString msec = QString::number((float)time.elapsed() / 1000, 'f', 3);
QString info = QString("%1 生成数据 (第 %2 条/总计 %3 条) 用时 %4 秒").arg(TIMEMS).arg(currentCount).arg(AppConfig::RowThread).arg(msec);
ui->textEdit->setTextColor("#22A3A9");
ui->textEdit->append(info);
} void frmDataThread::openFile()
{
QString info;
if (AppConfig::TypeThread == 0) {
info = QString("%1 导出完成 (共 %2 条/总计 %3 条) 用时 %4 秒").arg(TIMEMS)
.arg(AppConfig::RowThread).arg(AppConfig::RowThread).arg(xls->getUseTime());
} else {
info = QString("%1 导出完成 (共 %2 条/总计 %3 条) 用时 %4 秒").arg(TIMEMS)
.arg(AppConfig::RowThread).arg(AppConfig::RowThread).arg(pdf->getUseTime());
} ui->textEdit->setTextColor("#FD8B28");
ui->textEdit->append(info);
QTimer::singleShot(1000, this, SLOT(openFile2()));
} void frmDataThread::openFile2()
{
QUIHelper::openFile(fileName, "导出随机数据");
} void frmDataThread::appendFinshed(int count, int mesc)
{
QString time = QString::number((double)mesc / 1000, 'f', 3);
QString info = QString("%1 输出数据 (共 %2 条/总计 %3 条) 用时 %4 秒").arg(TIMEMS).arg(count).arg(AppConfig::RowThread).arg(time);
ui->textEdit->setTextColor("#D64D54");
ui->textEdit->append(info); //完成一个以后继续追加
append();
} void frmDataThread::on_btnStart_clicked()
{
//设置进度条
currentCount = 0;
ui->progressBar->setRange(0, AppConfig::RowThread);
ui->progressBar->setValue(currentCount);
ui->btnStart->setEnabled(false); //随机生成列名称和宽度
QList<QString> columnNames;
QList<int> columnWidths;
for (int j = 0; j < AppConfig::ColumnThread; j++) {
columnNames << QString("列%1").arg(j + 1);
columnWidths << 50;
} //第一步:设置文件名标题等
//第二步:打开文件
//第三步:启动线程执行 DataContent dataContent;
dataContent.sheetName = "测试名称";
dataContent.title = "测试标题";
dataContent.columnNames = columnNames;
dataContent.columnWidths = columnWidths;
//dataContent.randomColor = true; if (AppConfig::TypeThread == 0) {
fileName = QUIHelper::appPath() + "/db/dataout_thread.xls";
dataContent.fileName = fileName;
xls->setDataContent(dataContent);
xls->init();
xls->open();
xls->start();
} else {
//导出到pdf由于Qt自带类QPrint效率比较低所以数量过大弹个提示
if (AppConfig::RowThread >= 5000) {
QUIHelper::showMessageBoxInfo("数据量比较大用时比较久, 建议耐心等待最后完成!");
}
fileName = QUIHelper::appPath() + "/db/dataout_thread.pdf";
dataContent.fileName = fileName;
pdf->setDataContent(dataContent);
pdf->init();
pdf->open(true);
pdf->start();
} //立即执行一次
append();
}

Qt数据库应用5-海量数据多线程导出的更多相关文章

  1. qt数据库多线程问题的解决(QSqlDatabase只能在创建它的线程中使用)

    Qt数据库由QSqlDatabase::addDatabase()生成的QSqlDatabase只能在创建它的线程中使用, 在多线程中共用连接或者在另外一个线程中创建query都是不支持的几乎国内没有 ...

  2. SQL Server 之 在数据库之间进行数据导入导出

    1.同一服务器上数据库之间进行数据导入导出 (1).使用 SELECT INTO 导出数据 在SQL Server中使用最广泛的就是通过SELECT INTO语句导出数据,SELECT INTO语句同 ...

  3. MySQL数据库中.SQL文件的导出方式

    转自:http://tech.watchstor.com/management-117401.htm 在MySQL数据库中导入SQL文件是件很麻烦的事情,但是这是一项大家非常值得学习的技术,本文就从最 ...

  4. Qt添加驱动——Qt数据库之添加MySQL驱动插件

    Qt数据库之添加MySQL驱动插件(1) 现在可用的数据库驱动只有3种,在Qt中,我们需要自己编译其他数据库驱动的代码,让它们以插件的形式来使用.下面我们就以现在比较流行的MySQL数据库为例,说明一 ...

  5. Qt数据库_资料

    1. QT笔记_数据库总结(一)-rojian-ChinaUnix博客.html http://blog.chinaunix.net/uid-28194872-id-3631462.html (里面有 ...

  6. Postgresql数据库数据简单的导入导出

    Postgresql数据库数据简单的导入导出 博客分类: DataBase postgres  命令操作: 数据的导出:pg_dump -U postgres(用户名)  (-t 表名)  数据库名( ...

  7. Qt数据库 QSqlTableModel实例操作(转)

    本文介绍的是Qt数据库 QSqlTableModel实例操作,详细操作请先来看内容.与上篇内容衔接着,不顾本文也有关于上篇内容的链接. Qt数据库 QSqlTableModel实例操作是本文所介绍的内 ...

  8. C/C++ Qt 数据库与TreeView组件绑定

    在上一篇博文<C/C++ Qt 数据库QSql增删改查组件应用>介绍了Qt中如何使用SQL操作函数,并实现了对数据库的增删改查等基本功能,从本篇开始将实现数据库与View组件的绑定,通过数 ...

  9. C/C++ Qt 数据库与TableView多组件联动

    Qt 数据库组件与TableView组件实现联动,以下案例中实现了,当用户点击并选中TableView组件内的某一行时,我们通过该行中的name字段查询并将查询结果关联到ListView组件内,同时将 ...

  10. 解决POI多线程导出时数据错乱问题

    项目里有一个导出功能,但随着数据量大量上涨,导出时间长到不可忍受,遂重写此接口,多线程导出的代码并不复杂,每页有一条线程负责写入,利用线程池去调度,用countdownLatch保证在所有数据写完后再 ...

随机推荐

  1. kotlin协程——>组合挂起函数

    默认顺序调用 假设我们在不同的地⽅定义了两个进⾏某种调⽤远程服务或者进⾏计算的挂起函数.我们只假设它们都是有⽤的,但是实际上它们在这个⽰例中只是为了该⽬的⽽延迟了⼀秒钟: suspend fun do ...

  2. Springboot --- 使用国内的 AI 大模型 对话

    实在是不知道标题写什么了 可以在评论区给个建议哈哈哈哈 先用这个作为标题吧 尝试使用 国内给出的 AI 大模型做出一个 可以和 AI 对话的 网站出来 使用 智普AI 只能 在控制台中输出 对应的信息 ...

  3. 题解:AT_arc182_a [ARC182A] Chmax Rush!

    题目传送门 洛谷题解 思路 我们只需要枚举每一个 \(v_i\),对于 \(i\) 后面的 \(v_j\) 如果 \(v_i > v_j\) 进行以下讨论. \(p_i = p_j\) \(p_ ...

  4. Linux_进程理解、状态与优先级(详细版)

    1.进程的概念 课本概念:程序的一个执行实例,正在执行的程序等. 内核观点:担当分配系统资源(CPU时间,内存)的实体. 其实:进程=内核的相关管理数据结构(task_struct.页表等)+程序的代 ...

  5. 来看看一台Linux可支持多少个链接 | 漫画

    困惑很多人的并发问题 在网络开发中,我发现有很多同学对一个基础问题始终是没有彻底搞明白.那就是一台服务器最大究竟能支持多少个网络连接?我想我有必要单独发一篇文章来好好说一下这个问题. 很多同学看到这个 ...

  6. Java遇到PKIX path building failed错误的解决办法

    Java调用HTTPS可能出现如下错误: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderExc ...

  7. Linux 基础-文件及目录管理

    本文大部分内容参看 <Linux基础>一书,根据自己的工程经验和理解加以修改.拓展和优化形成了本篇博客,不适合 Linux 纯小白,适合有一定基础的开发者阅读. 一,概述 在 Linux ...

  8. Quartz集群增强版_00.How to use?(如何使用)

    Quartz集群增强版_00.How to use?(如何使用) 转载请著名出处 https://www.cnblogs.com/funnyzpc/p/18540378 开源地址 https://gi ...

  9. element-ui table 实现表格展开行每次只能展开一行

    1.table 部分 :row-key='getRowKeys':expand-row-keys="expands"@expand-change="expandSelec ...

  10. (Python基础教程之十八)Python字典交集–比较两个字典

    Python示例,用于查找2个或更多词典之间的常见项目,即字典相交项目. 1.使用"&"运算符的字典交集 最简单的方法是查找键,值或项的交集,即 & 在两个字典之间 ...