目录
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博客