Qt資料庫應用5-海量資料多執行緒匯出
阿新 • • 發佈:2022-01-21
一、前言
做資料匯出,少量的資料比如10W級別以下的,基本上直接佔用主執行緒也是很快的就可以處理完,上了百萬級別的資料量以後,就會發現效能極速下降,很容易卡主整體介面,於是這部分處理必須要用到執行緒,本資料匯出到xls元件採用xml格式的資料,固定的頭部和尾部資料,中間是一行行的資料,於是需要把這部分移到執行緒執行,使用者主動初始化類以後呼叫open方法開啟檔案,並先輸出好頭部資料,然後開啟執行緒,呼叫append方法逐行輸出資料,百萬千萬級別也可以慢慢輸出,執行緒排隊輸出到檔案,最後使用者主動呼叫close關閉檔案,輸出尾部資料,形成最終的檔案。
資料匯出到xls基本步驟:
- 開啟檔案,採用QTextStream輸出資料到檔案。
- 輸出固定頭部資訊。
- 輸出文件資訊。
- 輸出邊框樣式。
- 輸出表結構。
- 輸出欄位名稱。
- 逐行輸出資料。
- 輸出固定尾部資訊。
二、功能特點
- 元件同時集成了匯出資料到csv、xls、pdf和列印資料。
- 所有操作全部提供靜態方法無需new,資料和屬性等各種引數設定採用結構體資料,極為方便。
- 同時支援QTableView、QTableWidget、QStandardItemModel、QSqlTableModel等資料來源。
- 提供靜態方法直接傳入QTableView、QTableWidget控制元件,自動識別列名、列寬和資料內容。
- 每組功能都提供單獨的完整的示例,註釋詳細,非常適合各階段Qter程式設計師。
- 原創匯出資料機制,不依賴任何office元件或者作業系統等第三方庫,支援嵌入式linux。
- 速度超快,9個欄位10萬行資料只需要2秒鐘完成。
- 只需要四個步驟即可開始急速匯出海量資料比如100W條記錄到Excel。
- 同時提供直接寫入資料介面和多執行緒寫入資料介面,不卡主介面。
- 可設定標題、副標題、表名。
- 可設定匯出資料的欄位名、列名、列寬。
- 可設定末尾列自動拉伸填充,預設拉伸更美觀。
- 可設定是否啟用校驗過濾資料,啟用後符合規則的資料特殊顏色顯示。
- 可指定校驗的列、校驗規則、校驗值、校驗值資料型別。
- 校驗規則支援 精確等於==、大於>、大於等於>=、小於<、小於等於<=、不等於!=、包含contains。
- 校驗值資料型別支援 整型int、浮點型float、雙精度型double,預設文字字串型別。
- 可設定隨機背景顏色及需要隨機背景色的列集合。
- 支援分組輸出資料,比如按照裝置分組輸出資料,方便檢視。
- 可設定csv分隔符、行內容分隔符、子內容分隔符。
- 可設定邊框寬度、自動填資料型別,預設自動資料型別開啟。
- 可設定是否開啟資料單元格樣式,預設不開啟,不開啟可以節約大概30%的檔案體積。
- 可設定橫向排版、紙張邊距等,比如匯出到pdf以及列印資料。
- 支援圖文混排匯出資料到pdf以及列印資料,自動分頁。
- 靈活性超高,可自由更改原始碼設定對齊方式、文字顏色、背景顏色等。
- 支援任意excel表格軟體,包括但不限於excel2003-2021、wps、openoffice等。
- 純Qt編寫,支援任意Qt版本+任意編譯器+任意系統。
三、體驗地址
- 體驗地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取碼:o05q 檔名:bin_dataout.zip
- 國內站點:https://gitee.com/feiyangqingyun
- 國際站點:https://github.com/feiyangqingyun
- 個人主頁:https://blog.csdn.net/feiyangqingyun
- 知乎主頁: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();
}