QT中日志的使用案例 || 自动创建、管理、保存QT日志数据

server/2025/2/27 5:59:01/

目录

1.quiwidget.cpp

2.widget.cpp

3.widget.h

4.在需要记录日志的地方直接将信息插入即可

1. 释放 `m_fileLog` 和 `m_textStream`

1.1 为什么要关闭和删除 `m_fileLog` 和 `m_textStream`?

1.2 如果不这样做会有什么坏处?

 3. 总结

4.参考文章


需求分析:

        想实现在qt代码中对软件运行过程中容易出现的问题进行记录,将电量异常分析日志与平时详细日志进行分开存储。同时为了避免占用内存过大影响使用,需要每日对不是今天的文件夹进行清理,由于电量分析日志占用内存不大,目前,只对详细日志进行每日删除的操作以下是具体的一些实现思路。

1.quiwidget.cpp

#define TIMEMS          qPrintable(QTime::currentTime().toString("HH:mm:ss zzz"))
#define TIME            qPrintable(QTime::currentTime().toString("HH:mm:ss"))
#define QDATE           qPrintable(QDate::currentDate().toString("yyyy-MM-dd"))
#define QTIME           qPrintable(QTime::currentTime().toString("HH-mm-ss"))
#define DATETIME        qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
#define STRDATETIME     qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss"))
#define STRDATETIMEMS   qPrintable(QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss-zzz"))
#define RECORDFILE      qPrintable(QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss"))

2.widget.cpp

void Widget::writeLog(const QString &log, bool isChargeLog) {QString currentDate = QDate::currentDate().toString("yyyy-MM-dd");// 根据isChargeLog标志判断是充电异常日志还是详细日志QString logDir, logFileName,logDir2;// 选择路径和文件名if (isChargeLog) {logDir = QString("%1\\ChargeRecord\\%2").arg(m_strExeDir).arg(QDATE);logFileName = QString("%1\\ChargeLog_%2.txt").arg(logDir).arg(RECORDFILE);} else {logDir = QString("%1\\DetailedRecord\\%2").arg(m_strExeDir).arg(QDATE);logDir2 = QString("%1\\DetailedRecord").arg(m_strExeDir);logFileName = QString("%1\\DetailedRecord.txt").arg(logDir);// 删除非今天的文件夹和文件cleanupOldLogs(logDir2);}// 创建文件夹QDir temp;temp.mkpath(logDir);// 如果文件未被创建则创建文件if (m_fileLog == nullptr || m_fileLog->fileName() != logFileName) {if (m_fileLog != nullptr) {delete m_fileLog;  // 删除旧的文件对象}m_fileLog = new QFile(logFileName);bool ok = m_fileLog->open(QIODevice::ReadWrite | QIODevice::Append);if (ok) {// 赋值streamif (m_textStream != nullptr) {delete m_textStream;  // 删除旧的流对象}m_textStream = new QTextStream(m_fileLog);}}// 如果文件流准备好,写入日志if (m_textStream != nullptr) {QString logWithTimestamp = QString("[%1] %2").arg(DATETIME, log); // 添加时间戳*m_textStream << logWithTimestamp << endl;m_fileLog->flush();  // 立刻写入以防崩溃}
}void Widget::loadDetailedLog(){writeLog(QString("---------start----------"),false);writeLog(QString("状态转换m_nCurState【借卡:第一次交互前】 %1").arg(m_nCurState),false);writeLog(QString("---------end----------"),false);
}void Widget::onBtnqqClicked()
{ui->widgetLocker->saveSlotJson(m_strExeDir, PARAM_FILE_NAME);
}// 清除非今天的日志文件夹和文件
void Widget::cleanupOldLogs(const QString &logDir) {QDir dir(logDir);QStringList allDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);// 检查并删除所有不是今天日期的子文件夹for (const QString &folder : allDirs) {if (folder != QDate::currentDate().toString("yyyy-MM-dd")) {//qDebug() << "Deleting old log folder:" << folder;QDir oldDir(logDir + "\\" + folder);oldDir.removeRecursively();  // 删除该文件夹及其下的所有内容}}// 检查文件夹是否为空(删除空的文件夹)if (dir.entryList(QDir::Files).isEmpty() && dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot).isEmpty()) {dir.rmdir(logDir);  // 删除空文件夹}
}

3.widget.h

//wigdet.hpublic:void writeLog(const QString &log, bool isChargeLog);

4.在需要记录日志的地方直接将信息插入即可

    //记录日志QString num = QString::number(m_stCardInInfo.stSlotParam.nNum);QString onsite = QString::number(m_stCardInInfo.stSlotParam.stLt100Info.ucOnsite);QString cardNotSite = QString::number(m_stCardInInfo.stSlotParam.nCardNotSite);QString enable = QString::number(m_stCardInInfo.stSlotParam.nEnable);QString state = QString::number(m_stCardInInfo.stSlotParam.nState);QString cardStatus_flag = QString::number(m_stCardOutInfo.stSlotParam.cardStatus_flag);QString info = QString("归还的柜门状态 num: %1, Onsite: %2, CardNotSite: %3, Enable: %4, State: %5, bindState:%6").arg(num).arg(onsite).arg(cardNotSite).arg(enable).arg(state).arg(cardStatus_flag);writeLog(QString("%1").arg(info),false);

1. 释放 `m_fileLog` 和 `m_textStream`

1.1 为什么要关闭和删除 `m_fileLog` 和 `m_textStream`?

在 Qt 中,`QFile` 和 `QTextStream` 都是资源管理型的类,尤其是 `QFile` 负责文件的打开、关闭和读写操作,`QTextStream` 用于在文件中执行流式写入和读取。

- **关闭文件 (`m_fileLog->close()`)**:
  `QFile` 对象打开文件后,它会保持文件句柄(资源),直到文件被显式关闭。如果在程序结束时没有关闭文件,操作系统可能会认为文件仍然在使用中,导致以下问题:
  - **文件无法正确保存**:某些数据可能没有写入磁盘。
  - **文件句柄泄漏**:每个打开的文件都占用系统资源,如果程序没有释放文件句柄,操作系统可能会因为文件句柄数目耗尽而出现错误,尤其是在打开大量文件时。
  
  关闭文件是文件操作的最佳实践,它确保所有缓冲数据被刷新到磁盘,并且释放操作系统资源。

- **删除 `m_textStream`**:
  `QTextStream` 是一个指向 `QFile` 的流对象,负责将数据写入文件。`QTextStream` 本身是一个包装对象,不负责文件的实际打开和关闭,但是它依赖于 `QFile` 的存在。如果不手动删除 `QTextStream`,它将和 `QFile` 一起被销毁,但没有显式释放内存的话,会存在内存泄漏的风险。

1.2 如果不这样做会有什么坏处?

如果我们不关闭文件和删除 `QTextStream`,会有以下几个问题:

- **内存泄漏**:如果没有删除 `m_textStream`,它指向的内存就不会被释放,导致内存泄漏。
- **文件操作不完整**:如果不关闭文件,`QFile` 可能没有正确地将所有数据写入磁盘。即使没有写入错误,某些数据可能会丢失,因为文件未被正确刷新。
- **资源泄漏**:`QFile` 需要操作系统资源(如文件句柄),如果不手动关闭文件,这些资源就不会被释放。长时间运行的程序可能会导致文件句柄耗尽,导致系统不允许再打开新文件。

 3. 总结

在析构函数中进行资源释放(关闭文件、删除流对象、删除 `ui`)是良好的编程实践,具体原因如下:

- **文件关闭**:防止文件未完全保存、文件句柄泄漏等问题。
- **删除对象**:防止内存泄漏,确保内存得到及时释放。
- **UI 删除**:确保 Qt 控件的内存被及时清理,避免内存泄漏。

### 如果不这样做的坏处:

1. **文件未关闭**:数据可能未被写入文件,文件句柄资源可能泄漏,导致文件操作出错。
2. **内存泄漏**:没有手动删除 `m_textStream` 和其他动态分配的内存,程序可能会在退出时无法释放内存。
3. **系统资源泄漏**:如果没有释放文件句柄和其他系统资源,可能会耗尽操作系统资源,导致后续无法打开新文件或其他系统操作失败。

4.参考文章

Qt之第三方库‌日志log使用(四)_qt log-CSDN博客


http://www.ppmy.cn/server/170952.html

相关文章

陀螺匠·企业助手v1.8 产品介绍

陀螺匠企业助手是一套采用Laravel 9框架结合Swoole高性能协程服务与Vue.js前端技术栈构建的新型智慧企业管理与运营系统。该系统深度融合了客户管理、项目管理、审批流程自动化以及低代码开发平台&#xff0c;旨在为企业提供一站式、数字化转型的全方位解决方案&#xff0c;助力…

保姆级! 本地部署DeepSeek-R1大模型 安装Ollama Api 后,Postman本地调用 deepseek

要在Postman中访问Ollama API并调用DeepSeek模型,你需要遵循以下步骤。首先,确保你有一个有效的Ollama服务器实例运行中,并且DeepSeek模型已经被加载。 可以参考我的这篇博客 保姆级!使用Ollama本地部署DeepSeek-R1大模型 并java通过api 调用 具体的代码实现参考我这个博…

Touchgfx控件 BOX和textArea

(一)BOX 是TouchGFX中最轻量级的控件之一&#xff0c;因为它不需要读取任何像素数据或进行任何复杂计算。 因此&#xff0c;大部分平台会将方框视为非常快速的控件。特性如下&#xff1a; &#xff08;1&#xff09;一般用来显示背景或者覆盖。 &#xff08;2&#xff09;不会产…

AOP进阶-05.连接点

一.连接点 JoinPoint有两个&#xff0c;要使用org,aspectj.lang package com.gjw.aop;import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org…

low rank decomposition如何用于矩阵的分解

1. 什么是矩阵分解和低秩分解 矩阵分解是将一个矩阵表示为若干结构更简单或具有特定性质的矩阵的组合或乘积的过程。低秩分解&#xff08;Low Rank Decomposition&#xff09;是其中一种方法&#xff0c;旨在将原矩阵近似为两个或多个秩较低的矩阵的乘积&#xff0c;从而降低复…

开源基准测试模拟器:BlueROV2 水下机器人的控制(更改Z方向控制器)

开源基准测试模拟器:BlueROV2 水下机器人的控制(更改Z方向控制器) 将原有项目的z方向控制器由自适应滑膜控制器(ASMC)更改为自抗扰控制器(ADRC) 原Z控制器 更改为ADRC后图像 原自适应滑膜控制器代码 function u =

django model.object.filter 不等于多个值

关于Django中QuerySet.filter()的使用问题。首先&#xff0c;我会分别针对“不等于多个值”的代码开发问题和可能遇到的报错问题给出解答。 代码开发问题&#xff1a;QuerySet.filter()不等于多个值 在Django中&#xff0c;如果你想在查询中排除多个值&#xff0c;可以使用__i…

C++ Primer Plus第八章课后习题总结

1. 编写通常接受一个参数&#xff08;字符串的地址&#xff09;&#xff0c;并打印该字符串的函数。然而&#xff0c;如果提供了第二个参数&#xff08;int类型&#xff09;&#xff0c;且该参数不为0&#xff0c;则该函数打印字符串的次数将为该函数被调用的次数&#xff08;注…