新增gvf转csv

This commit is contained in:
anxinglong 2026-05-25 18:24:55 +08:00
parent 7bd14d8179
commit d8759e1318
10 changed files with 920 additions and 10 deletions

View File

@ -23,6 +23,7 @@
#include "EnergyScaleDataModel.h"
#include "DataCalcProcess/CoincidenceSpectrumProcess.h"
#include "BackgroundTaskListModel.h"
#include "GvfToCsv/GvfToCsv.h"
#include <QDebug>
using namespace DataProcessWorkPool;
@ -1073,3 +1074,67 @@ bool EnergyScaleaAntiCoincidenceDataTask::processTask()
return true;
}
QString GvfToCsvDataTask::GetTaskName()
{
return QStringLiteral(u"[%1]GVF文件转CSV处理").arg(this->GetProjectName());
}
void GvfToCsvDataTask::setGvfName(const QString& gvfName)
{
m_gvfName = gvfName;
}
void GvfToCsvDataTask::setCsvName(const QString& csvName)
{
QDir projectDir(csvName);
if (!projectDir.exists()) {
projectDir.mkpath(".");
}
m_csvName = projectDir.filePath("粒子数据_gvf.csv");
}
bool GvfToCsvDataTask::processTask()
{
QFileInfo csvFileInfo(m_csvName);
QDir csvDir = csvFileInfo.absoluteDir();
if (!csvDir.exists()) {
if (!csvDir.mkpath(".")) {
m_error = QStringLiteral(u"无法创建输出目录: %1").arg(csvDir.path());
LOG_ERROR(m_error.toUtf8().constData());
return false;
}
}
QString testFile = csvDir.filePath(".test_write.tmp");
QFile test(testFile);
if (!test.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
m_error = QStringLiteral(u"输出目录不可写: %1").arg(csvDir.path());
LOG_ERROR(m_error.toUtf8().constData());
return false;
}
test.remove();
if (m_gvfName.isEmpty() || m_csvName.isEmpty()) {
m_error = "GVF文件路径或CSV输出路径为空";
LOG_ERROR(m_error.toUtf8().constData());
return false;
}
std::unique_ptr<GvfToCsv> gvf2Csv(new GvfToCsv());
bool success = gvf2Csv->convertGVF2CSVSync(m_gvfName, m_csvName);
if (success) {
m_resultCsvPath = m_csvName;
m_conversionSuccess = true;
updateTaskResultData(QVariant(m_resultCsvPath));
} else {
m_error = gvf2Csv->getLastError();
m_conversionSuccess = false;
LOG_ERROR(QStringLiteral(u"GVF转换失败: %1")
.arg(m_error)
.toUtf8().constData());
}
return m_conversionSuccess;
}

View File

@ -7,7 +7,7 @@
#include "AnalysisTypeDefine.h"
#include <QMap>
#include <QVariant>
#include <QEventLoop>
class EnergyScaleDataModel;
class MeasureAnalysisProjectModel;
@ -167,6 +167,23 @@ namespace DataProcessWorkPool
private:
virtual bool processTask() override;
};
class GvfToCsvDataTask : public DataProcessTask
{
public:
QString GetTaskName() override;
void setGvfName(const QString& gvfName);
void setCsvName(const QString& csvName);
QString getError() const { return m_error; }
QString getResultCsvPath() const { return m_resultCsvPath; }
private:
bool processTask() override;
QString m_gvfName;
QString m_csvName;
QString m_resultCsvPath;
QString m_error;
bool m_conversionSuccess = false;
};
}
#endif // DATAPROCESSWORKPOOL_H

296
src/GvfToCsv/GvfToCsv.cpp Normal file
View File

@ -0,0 +1,296 @@
#include "GvfToCsv.h"
#include <QFile>
#include <QTextStream>
#include <QEventLoop>
#include <QTimer>
#include <QDir>
#include "GlobalDefine.h"
GvfToCsv::GvfToCsv(QObject *parent)
: QObject(parent)
{
connect(m_sqliteWorker.get(), &SQLiteReadWrite::operationCompleted,
this, &GvfToCsv::onSqliteOperationCompleted);
connect(m_sqliteWorker.get(), &SQLiteReadWrite::progressUpdated,
this, &GvfToCsv::conversionProgress);
connect(m_sqliteWorker.get(), &SQLiteReadWrite::logMessage,
this, [](const QString &msg) { qDebug() << "[GVF转换日志]" << msg; });
}
GvfToCsv::~GvfToCsv()
{
cleanUp();
if (m_syncEventLoop) {
delete m_syncEventLoop;
}
}
QList<ParticleData> GvfToCsv::parseParticleFrames(const QByteArray &data)
{
QList<ParticleData> particles;
const int minDataSize = GvfConst::HEADER_SIZE + GvfConst::PARTICLE_BLOCK_SIZE;
if (data.size() < minDataSize) {
qDebug() << "粒子数据长度不足,跳过解析";
return particles;
}
const quint8* rawData = reinterpret_cast<const quint8*>(data.constData());
if (rawData[0] != GvfConst::HEADER_BYTE1 || rawData[1] != GvfConst::HEADER_BYTE2) {
qDebug() << "粒子数据头部校验失败,跳过解析";
return particles;
}
const quint8* ptr = rawData + GvfConst::HEADER_SIZE;
int remaining = data.size() - GvfConst::HEADER_SIZE;
particles.reserve(remaining / GvfConst::PARTICLE_BLOCK_SIZE);
while (remaining >= GvfConst::PARTICLE_BLOCK_SIZE)
{
quint16 alignWord = qFromLittleEndian<quint16>(static_cast<const void*>(ptr));
quint8 lowByte = alignWord & 0xFF;
quint8 highByte = (alignWord >> 8) & 0xFF;
if (highByte != GvfConst::ALIGN_HIGH_BYTE) {
ptr += GvfConst::PARTICLE_BLOCK_SIZE;
remaining -= GvfConst::PARTICLE_BLOCK_SIZE;
continue;
}
const quint8 board = (lowByte >> 4) & 0x0F;
const quint8 channel = lowByte & 0x0F;
const int channelIndex = board * 4 + channel;
if (channelIndex >= GvfConst::MAX_CHANNEL_COUNT) {
ptr += GvfConst::PARTICLE_BLOCK_SIZE;
remaining -= GvfConst::PARTICLE_BLOCK_SIZE;
continue;
}
quint64 timestamp = 0;
const quint8* timestampPtr = ptr + 2;
for (int i = 0; i < 6; ++i) {
timestamp |= static_cast<quint64>(timestampPtr[i]) << (8 * i);
}
const quint16 amplitude = qFromLittleEndian<quint16>(static_cast<const void*>(ptr + 8));
const quint32 icr = qFromLittleEndian<quint32>(static_cast<const void*>(ptr + 10));
const quint16 riseTime = qFromLittleEndian<quint16>(static_cast<const void*>(ptr + 14));
const quint16 fallTime = qFromLittleEndian<quint16>(static_cast<const void*>(ptr + 16));
const int address = static_cast<int>(
static_cast<double>(amplitude) / GvfConst::AMPLITUDE_MAX * GvfConst::MAX_ADDRESS
);
ParticleData p(
board,
channel,
timestamp,
timestamp * GvfConst::TIME_PER_COUNT,
amplitude,
address,
icr,
riseTime,
fallTime
);
particles.append(p);
ptr += GvfConst::PARTICLE_BLOCK_SIZE;
remaining -= GvfConst::PARTICLE_BLOCK_SIZE;
}
return particles;
}
void GvfToCsv::cleanUp()
{
if (m_sqliteWorker) {
// 先断开所有信号连接
disconnect(m_sqliteWorker.get(), nullptr, this, nullptr);
// 停止操作
m_sqliteWorker->stopOperation();
// 等待操作完成
QEventLoop loop;
QTimer timeoutTimer;
timeoutTimer.setSingleShot(true);
connect(m_sqliteWorker.get(), &SQLiteReadWrite::operationCompleted, &loop, &QEventLoop::quit);
connect(&timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit);
timeoutTimer.start(3000);
loop.exec(QEventLoop::ExcludeUserInputEvents);
m_sqliteWorker.reset();
}
m_gvfPath.clear();
m_csvPath.clear();
m_lastError.clear();
}
bool GvfToCsv::convertGVF2CSVSync(const QString &gvfPath, const QString &csvPath)
{
if (!m_syncEventLoop) {
m_syncEventLoop = new QEventLoop();
}
bool result = false;
QObject signalReceiver;
connect(this, &GvfToCsv::conversionFinished, &signalReceiver, [&](bool success) {
result = success;
m_syncEventLoop->quit();
});
connect(this, &GvfToCsv::errorOccurred, &signalReceiver, [](const QString &msg) {
LOG_ERROR(QStringLiteral(u"GVF转换错误: %1").arg(msg).toUtf8().constData());
});
convertGVF2CSVAsync(gvfPath, csvPath);
m_syncEventLoop->exec();
return result;
}
void GvfToCsv::convertGVF2CSVAsync(const QString &gvfPath, const QString &csvPath)
{
m_lastError.clear();
cleanUp();
if (gvfPath.isEmpty() || csvPath.isEmpty()) {
setLastError("GVF/CSV路径不能为空");
emit conversionFinished(false);
return;
}
QFileInfo gvfFileInfo(gvfPath);
if (!gvfFileInfo.exists() || !gvfFileInfo.isFile()) {
setLastError(QString("GVF文件不存在: %1").arg(gvfPath));
emit conversionFinished(false);
return;
}
QFileInfo csvFileInfo(csvPath);
QDir csvDir = csvFileInfo.absoluteDir();
if (!csvDir.exists() && !csvDir.mkpath(".")) {
setLastError(QString("无法创建CSV目录: %1").arg(csvDir.path()));
emit conversionFinished(false);
return;
}
m_gvfPath = gvfPath;
m_csvPath = csvPath;
m_sqliteWorker = std::make_unique<SQLiteReadWrite>(this);
connect(m_sqliteWorker.get(), &SQLiteReadWrite::operationCompleted,
this, &GvfToCsv::onSqliteOperationCompleted, Qt::QueuedConnection);
connect(m_sqliteWorker.get(), &SQLiteReadWrite::progressUpdated,
this, &GvfToCsv::conversionProgress, Qt::QueuedConnection);
if (!m_sqliteWorker->openDatabase(m_gvfPath)) {
setLastError(QString("打开GVF数据库失败: %1").arg(m_gvfPath));
emit conversionFinished(false);
return;
}
m_sqliteWorker->startReadWriteOperation();
}
void GvfToCsv::onSqliteOperationCompleted(bool success, const QString &msg)
{
if (!success) {
setLastError(QString("GVF数据读取失败: %1").arg(msg));
cleanUp();
emit conversionFinished(false);
return;
}
try {
processDBData();
emit conversionFinished(true);
} catch (const std::exception &e) {
setLastError(QString("CSV写入异常: %1").arg(e.what()));
emit conversionFinished(false);
} catch (...) {
setLastError("CSV写入未知异常");
emit conversionFinished(false);
}
cleanUp();
}
void GvfToCsv::processDBData()
{
QVector<DataBaseStruct> dbList = m_sqliteWorker->DataBaseList();
if (dbList.isEmpty()) {
throw std::runtime_error("GVF数据库中无任何记录");
}
QFile outFile(m_csvPath);
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
throw std::runtime_error(QString("无法创建CSV文件: %1错误: %2")
.arg(m_csvPath)
.arg(outFile.errorString())
.toStdString());
}
QTextStream out(&outFile);
out.setCodec("UTF-8");
out << QStringLiteral(u"板卡号,通道号,道址,时间计数\n");
QString csvBuffer;
csvBuffer.reserve(4 * 1024 * 1024); // 4MB缓冲区
quint64 totalParticles = 0;
int emptyFrameCount = 0;
int processedFrames = 0;
const int totalFrames = dbList.size();
for (const auto &data : dbList) {
QList<ParticleData> particles = parseParticleFrames(data.data);
if (particles.isEmpty()) {
emptyFrameCount++;
} else {
totalParticles += particles.size();
for (const auto &p : particles) {
csvBuffer += QString("%1,%2,%3,%4\n")
.arg(p.boardId)
.arg(p.channelId)
.arg(p.address)
.arg(p.timestampCount);
}
}
if (csvBuffer.size() >= 4 * 1024 * 1024) {
out << csvBuffer;
csvBuffer.clear();
}
processedFrames++;
if (processedFrames % 1000 == 0) {
int remainingFrames = totalFrames - processedFrames;
int progress = (processedFrames * 100) / totalFrames;
emit conversionProgress(progress);
}
}
if (!csvBuffer.isEmpty()) {
out << csvBuffer;
}
out.flush();
outFile.close();
if (outFile.error() != QFile::NoError) {
throw std::runtime_error(QString("CSV文件写入失败: %1错误: %2")
.arg(m_csvPath)
.arg(outFile.errorString())
.toStdString());
}
if (totalParticles == 0) {
QFile::remove(m_csvPath);
throw std::runtime_error(QString("GVF文件中未解析到任何有效粒子数据空帧数: %1")
.arg(emptyFrameCount)
.toStdString());
}
emit conversionProgress(100);
}

88
src/GvfToCsv/GvfToCsv.h Normal file
View File

@ -0,0 +1,88 @@
#ifndef GVFTOCSV_H
#define GVFTOCSV_H
#include "sqliteread.h"
#include <QObject>
#include <QString>
#include <QByteArray>
#include <memory>
#include <QDebug>
#include <QtCore>
#include <QtEndian>
// 常量定义:替换魔法数,提升可读性和可维护性
namespace GvfConst {
constexpr quint8 HEADER_BYTE1 = 0xA7; // 头部固定字节1
constexpr quint8 HEADER_BYTE2 = 0xA2; // 头部固定字节2
constexpr int HEADER_SIZE = 3; // 头部总字节数
constexpr int PARTICLE_BLOCK_SIZE = 20; // 单个粒子数据块大小
constexpr quint8 ALIGN_HIGH_BYTE = 0xFE; // 对齐标记高字节
constexpr int MAX_CHANNEL_COUNT = 32; // 硬件最大通道数
constexpr double CLOCK_FREQ_MHZ = 200.0; // 时钟频率(200MHz)
constexpr double TIME_PER_COUNT = 1.0 / (CLOCK_FREQ_MHZ * 1e6); // 单计数时间(5ns)
constexpr int MAX_ADDRESS = 4096; // 最大道址
constexpr int AMPLITUDE_MAX = 65535; // 幅度最大值
}
struct ParticleData {
int boardId = 0; // 板卡号 (0-15)
int channelId = 0; // 通道号 (0-15)
quint64 timestampCount = 0; // 原始时间计数6字节
double timeSeconds = 0.0; // 换算后的时间(秒)
quint16 amplitude = 0; // 原始幅度值 (0-65535)
int address = 0; // 转换后的道址
quint32 icr = 0; // 输入计数率相关值
quint16 riseTime = 0; // 上升时间
quint16 fallTime = 0; // 下降时间
// 添加构造函数
ParticleData() = default; // 保留默认构造
ParticleData(int board, int ch, quint64 ts, double ts_sec,
quint16 amp, int addr, quint32 icr_val,
quint16 rise, quint16 fall)
: boardId(board)
, channelId(ch)
, timestampCount(ts)
, timeSeconds(ts_sec)
, amplitude(amp)
, address(addr)
, icr(icr_val)
, riseTime(rise)
, fallTime(fall)
{}
};
class GvfToCsv : public QObject
{
Q_OBJECT
public:
explicit GvfToCsv(QObject *parent = nullptr);
~GvfToCsv() override;
void convertGVF2CSVAsync(const QString &gvfPath, const QString &csvPath);
// 添加同步转换方法
bool convertGVF2CSVSync(const QString &gvfPath, const QString &csvPath);
// 添加错误信息获取
QString getLastError() const { return m_lastError; }
signals:
void conversionProgress(int percent);
void conversionFinished(bool success);
void errorOccurred(const QString &msg);
private slots:
void onSqliteOperationCompleted(bool success, const QString &msg);
private:
void processDBData();
QList<ParticleData> parseParticleFrames(const QByteArray &data);
void cleanUp();
// 添加错误信息存储
void setLastError(const QString& error) { m_lastError = error; emit errorOccurred(error); }
std::unique_ptr<SQLiteReadWrite> m_sqliteWorker;
QString m_gvfPath;
QString m_csvPath;
QString m_lastError;
// 用于同步转换
QEventLoop* m_syncEventLoop = nullptr;
};
#endif // GVFTOCSV_H

276
src/GvfToCsv/sqliteread.cpp Normal file
View File

@ -0,0 +1,276 @@
#include "sqliteread.h"
#include <QtConcurrent>
SQLiteReadWrite::SQLiteReadWrite(QObject *parent)
: QObject(parent)
{
m_connectionName = QString("SQLiteConnection_%1").arg(reinterpret_cast<quintptr>(this));
idValue = 0;
m_stopRequested = false;
}
SQLiteReadWrite::~SQLiteReadWrite()
{
if (!m_isClosed) {
closeDatabase();
}
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
}
bool SQLiteReadWrite::openDatabase(const QString &dbPath)
{
QMutexLocker locker(&m_mutex);
if (!m_isClosed) {
closeDatabase();
}
// 确定数据库路径
QString path = dbPath;
if (path.isEmpty()) {
QString appDir = QCoreApplication::applicationDirPath();
path = QDir(appDir).filePath("test_readwrite.db");
}
m_dbPath = path;
// 打开数据库
m_database = QSqlDatabase::addDatabase("QSQLITE", m_connectionName);
m_database.setDatabaseName(m_dbPath);
if (!m_database.open()) {
log(QString("打开数据库失败: %1").arg(m_database.lastError().text()));
return false;
}
// 启用外键和WAL模式提高并发性能
QSqlQuery query(m_database);
// 开启外键约束
if (!query.exec("PRAGMA foreign_keys = ON;")) {
log(QString("启用外键失败: %1").arg(query.lastError().text()));
}
// 开启WAL模式写时复制提高读写并发性能
if (!query.exec("PRAGMA journal_mode = WAL;")) {
log(QString("启用WAL模式失败: %1").arg(query.lastError().text()));
}
// // 设置同步模式(在安全性和性能之间权衡)
// if (!query.exec("PRAGMA synchronous = NORMAL;")) {
// log(QString("设置同步模式失败: %1").arg(query.lastError().text()));
// }
// 设置缓存大小
if (!query.exec("PRAGMA cache_size = 10000;")) {
log(QString("设置缓存大小失败: %1").arg(query.lastError().text()));
}
m_isClosed = false;
log(QString("数据库打开成功: %1").arg(m_dbPath));
return true;
}
void SQLiteReadWrite::closeDatabase()
{
QMutexLocker locker(&m_mutex);
if (m_isClosed) {
return;
}
m_isClosed = true;
if (m_database.isOpen()) {
m_database.close();
log("数据库已关闭");
}
if (QSqlDatabase::contains(m_connectionName)) {
QSqlDatabase::removeDatabase(m_connectionName);
}
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
}
void SQLiteReadWrite::startReadWriteOperation()
{
if (!m_database.isOpen()) {
emit operationCompleted(false, "数据库未打开");
return;
}
m_stopRequested = false;
//在单独的线程中执行避免阻塞UI
QtConcurrent::run(this, &SQLiteReadWrite::processReadWrite);
}
void SQLiteReadWrite::stopOperation()
{
m_stopRequested = true;
log("stop requese send");
}
void SQLiteReadWrite::processReadWrite()
{
m_timer.start();
log("开始边读边写操作...");
try {
processWithMultipleConnections();
if (!m_stopRequested) {
qint64 elapsed = m_timer.elapsed();
QString message = QString("操作完成,总耗时: %1 毫秒").arg(elapsed);
log(message);
emit operationCompleted(true, message);
} else {
emit operationCompleted(false, "quxiao");
}
} catch (const std::exception &e) {
log(QString("发生异常: %1").arg(e.what()));
emit operationCompleted(false, QString("异常: %1").arg(e.what()));
}
}
void SQLiteReadWrite::processWithMultipleConnections()
{
const QString readConnName = m_connectionName + "_read";
int totalRecords = 0;
int processedRecords = 0;
bool readSuccess = false;
{
QSqlDatabase readDb = QSqlDatabase::addDatabase("QSQLITE", readConnName);
readDb.setDatabaseName(m_dbPath);
if (!readDb.open()) {
QString logMsg = QString("打开读取连接失败: %1").arg(readDb.lastError().text());
log(logMsg.toUtf8().constData());
emit operationCompleted(false, "无法打开数据库连接");
return;
}
{
QSqlQuery optimizeQuery(readDb);
optimizeQuery.exec("PRAGMA journal_mode = WAL;");
optimizeQuery.exec("PRAGMA synchronous = OFF;");
optimizeQuery.exec("PRAGMA cache_size = -200000;"); // 200MB缓存
optimizeQuery.exec("PRAGMA temp_store = MEMORY;");
optimizeQuery.exec("PRAGMA mmap_size = 2147483648;"); // 2GB内存映射
optimizeQuery.exec("PRAGMA query_only = ON;");
optimizeQuery.finish();
}
{
QSqlQuery countQuery(readDb);
if (countQuery.exec("SELECT COUNT(*) FROM lmdatainfov2")) {
countQuery.next();
totalRecords = countQuery.value(0).toInt();
}
countQuery.finish();
}
if (totalRecords == 0) {
log("数据库中无记录");
readDb.close();
emit operationCompleted(false, "数据库中无有效数据");
return;
}
QString totalMsg = QString("GVF数据库总记录数: %1 条").arg(totalRecords);
log(totalMsg.toUtf8().constData());
const int pageSize = 200;
int lastId = 0;
m_DataBaseList.clear();
m_DataBaseList.reserve(totalRecords);
while (!m_stopRequested) {
QSqlQuery readQuery(readDb);
readQuery.setForwardOnly(true);
readQuery.prepare("SELECT id, data FROM lmdatainfov2 WHERE id > :lastId ORDER BY id LIMIT :limit");
readQuery.bindValue(":lastId", lastId);
readQuery.bindValue(":limit", pageSize);
if (!readQuery.exec()) {
QString errMsg = QString("数据读取失败: %1").arg(readQuery.lastError().text());
log(errMsg.toUtf8().constData());
readQuery.finish();
break;
}
int pageRecords = 0;
while (readQuery.next() && !m_stopRequested) {
DataBaseStruct data;
data.id = readQuery.value(0).toInt();
data.data = readQuery.value(1).toByteArray();
m_DataBaseList.append(data);
lastId = data.id;
pageRecords++;
}
readQuery.finish();
readQuery.clear();
if (pageRecords == 0) {
break;
}
processedRecords += pageRecords;
int remainingRecords = totalRecords - processedRecords;
int progress = (processedRecords * 100) / totalRecords;
emit progressUpdated(progress, processedRecords, totalRecords);
}
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
readDb.close();
readSuccess = true;
}
QThread::msleep(50);
if (QSqlDatabase::contains(readConnName)) {
QSqlDatabase::removeDatabase(readConnName);
}
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
}
QSqlDatabase SQLiteReadWrite::createConnection()
{
QString connName = QString("TempConnection_%1_%2")
.arg(m_connectionName)
.arg(QDateTime::currentMSecsSinceEpoch());
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", connName);
db.setDatabaseName(m_dbPath);
if (!db.open()) {
log(QString("创建临时连接失败: %1").arg(db.lastError().text()));
}
return db;
}
void SQLiteReadWrite::log(const QString &message)
{
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
QString logMsg = QString("[%1] %2").arg(timestamp).arg(message);
emit logMessage(logMsg);
}
QVector<DataBaseStruct> SQLiteReadWrite::DataBaseList() const
{
QMutexLocker locker(&m_mutex);
return m_DataBaseList;
}
void SQLiteReadWrite::setIdValue(int value)
{
idValue = value;
}

89
src/GvfToCsv/sqliteread.h Normal file
View File

@ -0,0 +1,89 @@
// sqlitereadwrite.h
#ifndef SQLITERREADWRITE_H
#define SQLITERREADWRITE_H
#include <QObject>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QThread>
#include <QMutex>
#include <QAtomicInteger>
#include <QElapsedTimer>
#include <QDebug>
#include <QDir>
#include <QCoreApplication>
struct DataBaseStruct
{
int id;//ID
int curdevconfigindex;
int orgdevconfigindex;
int icr;
int datanum;
int tick;
QByteArray data;
QString reserve;
};
class SQLiteReadWrite : public QObject
{
Q_OBJECT
public:
explicit SQLiteReadWrite(QObject *parent = nullptr);
~SQLiteReadWrite();
bool openDatabase(const QString &dbPath);
void closeDatabase();
// 边读边写操作
void startReadWriteOperation();
void stopOperation();
void setIdValue(int value);
QVector<DataBaseStruct> DataBaseList() const;
signals:
void progressUpdated(int percent, qint64 processed, qint64 total);
void operationCompleted(bool success, const QString &message);
void logMessage(const QString &message);
void emitReadId(int readId);
void emitStopTime();
private slots:
void processReadWrite();
private:
// 数据库连接管理
QSqlDatabase m_database;
QString m_dbPath;
// 线程安全
mutable QMutex m_mutex;
QAtomicInteger<bool> m_stopRequested{false};
// 性能统计
QElapsedTimer m_timer;
// 连接名(确保多线程连接唯一性)
QString m_connectionName;
// 私有方法
QSqlDatabase createConnection();
// 具体操作
void processWithMultipleConnections();
void log(const QString &message);
int idValue;
QVector<DataBaseStruct> m_DataBaseList;
bool m_isClosed = true;
};
#endif // SQLITERREADWRITE_H

View File

@ -20,7 +20,7 @@
<x>0</x>
<y>0</y>
<width>892</width>
<height>23</height>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_measurement_analysis">

View File

@ -7,7 +7,7 @@
#include <QFileInfo>
#include <QTimer>
#include "DataProcessWorkPool.h"
#include "GlobalDefine.h"
NewMeasureAnalysisDlg::NewMeasureAnalysisDlg(QWidget *parent)
: QDialog(parent)
, ui(new Ui::NewMeasureAnalysisDlg)
@ -242,17 +242,33 @@ void NewMeasureAnalysisDlg::on_btn_ok_clicked()
QMessageBox::warning(this, QStringLiteral(u"警告"), QStringLiteral(u"创建测量分析项目工作目录失败:\n%1!").arg(project_dir_path));
return;
}
if ( ui->checkBox_file_data->isChecked() ) {
if ( ui->checkBox_file_data->isChecked() )
{
const QString& data_file_path = ui->lineEdit_filename->property("data_file_path").toString();
if (data_file_path.isEmpty()) {
QMessageBox::warning(this, QStringLiteral(u"警告"), QStringLiteral(u"请选择粒子数据文件!"));
return;
}
auto separate_task = new DataProcessWorkPool::ParticleDataSortByMinimysTask;
separate_task->SetAllChannelParticleDataFilename(data_file_path);
separate_task->SetSortedResultDir(project_dir_path);
separate_task->SetFinishedNotifier(this, "onNewProjectFromFileFinished", project_name);
separate_task->StartTask();
if(QFileInfo(data_file_path).suffix().toLower() == "gvf")
{
// 正确使用任务池处理GVF转换
auto gvfTask = new DataProcessWorkPool::GvfToCsvDataTask;
gvfTask->setGvfName(data_file_path);
gvfTask->setCsvName(project_dir_path);
gvfTask->SetFinishedNotifier(this, "onGvfConversionFinished", project_name);
gvfTask->StartTask();
}
else
{
// 直接处理CSV文件
startParticleSortTask(data_file_path, project_name, project_dir_path);
}
// auto separate_task = new DataProcessWorkPool::ParticleDataSortByMinimysTask;
// separate_task->SetAllChannelParticleDataFilename(data_file_path);
// separate_task->SetSortedResultDir(project_dir_path);
// separate_task->SetFinishedNotifier(this, "onNewProjectFromFileFinished", project_name);
// separate_task->StartTask();
ui->stackedWidget->setEnabled(false);
ui->label_note->setEnabled(false);
@ -274,3 +290,59 @@ void NewMeasureAnalysisDlg::on_btn_ok_clicked()
// separate_task->SetFinishedNotifier(this->_tree_measure_analysis, "onFinishedSeparateEveryChannelParticleData", project_name);
// separate_task->StartTask();
}
// 添加新的槽函数处理GVF转换完成
void NewMeasureAnalysisDlg::onGvfConversionFinished(bool ok, const QString& project_name, const QVariant &data)
{
this->_task_wait_timer->stop();
ui->progressBar->setValue(100);
if (ok) {
QString csvFilePath = data.toString();
QFileInfo fileInfo(csvFilePath);
if (fileInfo.exists() && fileInfo.size() > 100) {
startParticleSortTask(csvFilePath, project_name, fileInfo.absolutePath());
return;
} else {
ok = false;
QString errorMsg;
if (!fileInfo.exists()) {
errorMsg = QStringLiteral(u"输出文件不存在: %1").arg(csvFilePath);
} else {
errorMsg = QStringLiteral(u"输出文件为空: %1").arg(csvFilePath);
QFile::remove(csvFilePath);
}
LOG_ERROR(errorMsg.toUtf8().constData());
}
}
QString projects_dir_path = QDir(qApp->applicationDirPath()).filePath("Projects");
QString project_dir_path = QDir(projects_dir_path).filePath(project_name);
QDir project_dir(project_dir_path);
if (project_dir.exists()) {
project_dir.removeRecursively();
}
QMessageBox::critical(this, QStringLiteral(u"GVF转换失败"),
QStringLiteral(u"错误信息: %1\n\n请检查GVF文件格式是否正确。")
.arg(data.isValid() ? data.toString() : "未知错误"));
ui->progressBar->setVisible(false);
ui->stackedWidget->setEnabled(true);
ui->label_note->setEnabled(true);
ui->plainTextEdit_description->setEnabled(true);
ui->btn_previous_step->setEnabled(true);
ui->btn_next_step->setEnabled(true);
ui->btn_ok->setEnabled(true);
}
void NewMeasureAnalysisDlg::startParticleSortTask(const QString& data_file_path,
const QString& project_name,
const QString& project_dir_path)
{
auto separate_task = new DataProcessWorkPool::ParticleDataSortByMinimysTask;
separate_task->SetAllChannelParticleDataFilename(data_file_path);
separate_task->SetSortedResultDir(project_dir_path);
separate_task->SetFinishedNotifier(this, "onNewProjectFromFileFinished", project_name);
separate_task->StartTask();
}

View File

@ -20,10 +20,13 @@ public:
private:
void initialization();
void newProject(const QString &particle_data_filename = QString());
void startParticleSortTask(const QString& data_file_path,
const QString& project_name,
const QString& project_dir_path);
private slots:
void onNewProjectFromFileFinished(bool ok, const QString& project_name, const QVariant &data);
void on_btn_ok_clicked();
void onGvfConversionFinished(bool ok, const QString& project_name, const QVariant &data);
private:
Ui::NewMeasureAnalysisDlg *ui;

View File

@ -83,6 +83,8 @@ SOURCES += \
EnergyCountPlotView/EnergyCountPlotView.cpp \
EnergyScaleDataModel.cpp \
EnergyScaleForm.cpp \
GvfToCsv/GvfToCsv.cpp \
GvfToCsv/sqliteread.cpp \
MainWindow.cpp \
MeasureAnalysisDataTableView/MeasureAnalysisDataTableView.cpp \
MeasureAnalysisHistoryForm/MeasureAnalysisHistoryForm.cpp \
@ -136,6 +138,8 @@ HEADERS += \
EnergyScaleDataModel.h \
EnergyScaleForm.h \
GlobalDefine.h \
GvfToCsv/GvfToCsv.h \
GvfToCsv/sqliteread.h \
MainWindow.h \
MeasureAnalysisDataTableView/MeasureAnalysisDataTableView.h \
MeasureAnalysisHistoryForm/MeasureAnalysisHistoryForm.h \