Qt 日志文件的滚动写入

Qt 日志文件的滚动写入

flyfish

日志文件的滚动写入功能。在日志文件达到10MB时创建新的日志文件,并且在总日志文件大小达到10GB时开始覆盖最早的日志文件

以监控一个文件夹的写日志为例

日志文件创建与管理

初始化日志文件:在FileMonitor类的构造函数中,会创建第一个日志文件。日志文件的命名格式为 "file_monitor_序号.log",初始序号为 0。

滚动写入机制:

单个日志文件大小限制:当向当前日志文件写入内容使得其大小达到 10MB(通过logFileSizeLimit变量设定,值为10 * 1024 * 1024字节)时,会关闭当前日志文件,增加日志文件索引,然后创建新的日志文件用于后续的日志记录。

总日志文件大小限制:

同时,会监控所有日志文件的总体大小,当总大小达到 10GB(通过totalLogSizeLimit变量设定,值为10 * 1024 * 1024 * 1024字节)时,会删除最早创建的日志文件(通过计算最早日志文件的文件名并判断其是否存在,若存在则删除),以确保总日志文件大小不会无限制增长。

日志内容记录:

对于文件创建、删除、修改等事件,会将事件发生的当前日期时间(格式为 "yyyy-MM-dd hh:mm:ss")、事件类型(如 "File created"、"File deleted"、"File modified")以及相关文件的路径信息,按照特定格式写入到当前正在使用的日志文件中。并且每次写入后会立即刷新缓冲区,确保日志内容及时写入文件。同时,会实时更新当前日志文件的大小信息,以便判断是否达到单个日志文件大小限制。

c 复制代码
#include <QCoreApplication>
#include <QFileSystemWatcher>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include <QSet>
#include <iostream>

// FileMonitor类继承自QObject,用于监控指定文件夹的文件变化并记录相关日志
class FileMonitor : public QObject {
    Q_OBJECT

public:
    // 构造函数,用于初始化文件监控器相关参数
    explicit FileMonitor(const QString &path, QObject *parent = nullptr)
        : QObject(parent),
          // 创建文件系统监控器对象,并将其作为当前对象的子对象
          watcher(new QFileSystemWatcher(this)),
          rootPath(path),
          // 设置单个日志文件的大小限制为10MB,这里将10MB转换为字节数
          logFileSizeLimit(static_cast<quint64>(10) * 1024 * 1024),
          // 设置总日志文件大小限制为10GB,同样转换为字节数
          totalLogSizeLimit(static_cast<quint64>(10) * 1024 * 1024 * 1024),
          currentLogFileIndex(0),
          currentLogFileSize(0) {

        // 将指定的监控路径添加到文件系统监控器中
        watcher->addPath(rootPath);

        // 获取监控路径下初始的文件列表
        QDir dir(rootPath);
        initialFiles = dir.entryList(QDir::Files);

        // 连接文件系统监控器的目录变化信号到对应的槽函数
        connect(watcher, &QFileSystemWatcher::directoryChanged, this, &FileMonitor::onDirectoryChanged);
        // 连接文件系统监控器的文件变化信号到对应的槽函数
        connect(watcher, &QFileSystemWatcher::fileChanged, this, &FileMonitor::onFileChanged);

        // 初始化日志文件,创建第一个日志文件
        createNewLogFile();
    }

private slots:
    // 当监控的目录发生变化时调用的槽函数
    void onDirectoryChanged(const QString &path) {
        std::cout << "Directory changed: " << qPrintable(path) << std::endl;

        // 获取当前监控目录下的文件列表
        QDir dir(rootPath);
        QStringList currentFiles = dir.entryList(QDir::Files);

        // 找出新增的文件,通过集合运算实现
        QSet<QString> newFiles = QSet<QString>(currentFiles.begin(), currentFiles.end()).subtract(QSet<QString>(initialFiles.begin(), initialFiles.end()));
        // 遍历新增的文件,记录文件创建事件到日志
        for (const QString &file : newFiles) {
            logEvent("File created", dir.absoluteFilePath(file));
        }

        // 找出被删除的文件,同样通过集合运算
        QSet<QString> deletedFiles = QSet<QString>(initialFiles.begin(), initialFiles.end()).subtract(QSet<QString>(currentFiles.begin(), currentFiles.end()));
        // 遍历被删除的文件,记录文件删除事件到日志
        for (const QString &file : deletedFiles) {
            logEvent("File deleted", dir.absoluteFilePath(file));
        }

        // 更新初始文件列表,使其为当前的文件列表,以便下次检测文件变化
        initialFiles = currentFiles;
    }

    // 当监控的文件发生变化时调用的槽函数
    void onFileChanged(const QString &path) {
        std::cout << "File changed: " << qPrintable(path) << std::endl;
        // 记录文件修改事件到日志
        logEvent("File modified", path);
    }

private:
    // 创建新的日志文件的函数
    void createNewLogFile() {
        // 构造新的日志文件名,格式为:file_monitor_序号.log
        QString logFileName = "file_monitor_" + QString::number(currentLogFileIndex) + ".log";
        currentLogFile.setFileName(logFileName);

        // 如果日志文件已经存在,获取其大小并更新当前日志文件大小变量
        if (currentLogFile.exists()) {
            currentLogFileSize = currentLogFile.size();
        } else {
            currentLogFileSize = 0;
        }

        // 打开或创建日志文件,如果失败则输出错误信息
        if (!currentLogFile.open(QIODevice::Append | QIODevice::Text)) {
            std::cerr << "Failed to open/create log file: " << qPrintable(logFileName) << std::endl;
        }
    }

    // 记录日志事件的函数
    void logEvent(const QString &event, const QString &path) {
        // 创建文本流对象,用于向当前日志文件写入内容
        QTextStream out(&currentLogFile);
        // 写入当前日期时间、事件类型和文件路径信息到日志文件
        out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
            << " - " << event << ": " << path << "\n";
        currentLogFile.flush();

        // 计算刚写入的日志字符串的大小,先读取文本流中的内容
        QString logString = out.readAll();
        // 如果读取为空,说明可能是因为刚刚写入还未缓存,重新构造日志字符串
        if (logString.isEmpty()) {
            logString = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
                        + " - " + event + ": " + path + "\n";
        }

        // 更新当前日志文件的大小,将日志字符串转换为UTF-8编码后计算其字节数并累加到当前日志文件大小变量
        currentLogFileSize += logString.toUtf8().size();

        // 检查当前日志文件大小是否达到单个日志文件大小限制
        if (currentLogFileSize >= logFileSizeLimit) {
            // 关闭当前日志文件
            currentLogFile.close();

            // 增加日志文件索引,用于创建下一个新的日志文件
            ++currentLogFileIndex;

            // 检查是否超过了总日志文件大小限制,如果超过则删除最早的日志文件
            if (currentLogFileIndex * logFileSizeLimit > totalLogSizeLimit) {
                QString oldestLogFileName = "file_monitor_" + QString::number(currentLogFileIndex - totalLogSizeLimit / logFileSizeLimit) + ".doc";
                if (QFile::exists(oldestLogFileName)) {
                    QFile::remove(oldestLogFileName);
                }
            }

            // 创建新的日志文件
            createNewLogFile();
        }
    }

    // 文件系统监控器对象,用于监控指定路径下的文件和目录变化
    QFileSystemWatcher *watcher;
    // 监控的根路径
    QString rootPath;
    // 初始的文件列表,用于对比检测文件的新增和删除情况
    QStringList initialFiles;

    // 以下是新增的日志管理相关成员变量

    // 当前正在使用的日志文件对象
    QFile currentLogFile;
    // 单个日志文件的大小限制,单位为字节
    quint64 logFileSizeLimit;
    // 总日志文件大小限制,单位为字节
    quint64 totalLogSizeLimit;
    // 当前日志文件的索引,用于区分不同的日志文件
    quint64 currentLogFileIndex;
    // 当前日志文件的大小,单位为字节,用于实时监控文件大小是否达到限制
    quint64 currentLogFileSize;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 获取命令行参数,如果有参数则将其作为监控路径,否则默认监控根目录
    QString watchPath = (argc > 1)? QString::fromLocal8Bit(argv[1]) : "/";

    // 创建文件监控对象,传入监控路径
    FileMonitor monitor(watchPath);

    // 运行应用程序的事件循环,开始监控文件和目录变化并记录日志
    return a.exec();
}

#include "main.moc"
相关推荐
feiyangqingyun1 小时前
Qt/C++离线地图的加载和交互/可以离线使用/百度和天地图离线/支持手机上运行
c++·qt·qt天地图·qt离线地图·qt地图导航
gz945615 小时前
windows下,用CMake编译qt项目,出现错误By not providing “FindQt5.cmake“...
开发语言·qt
「QT(C++)开发工程师」16 小时前
Ubuntu 26.04 LTS 大升级:Qt 6 成为未来新引擎
qt
兆。17 小时前
python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具
爬虫·python·qt
喝哈喝哈19 小时前
pycharm中配置pyqt5
python·qt·pycharm
Qt云程序员1 天前
Qt、C++实现五子棋人机对战与本地双人对战(高难度AI,极少代码)
c++·人工智能·qt
嵌R式小Z1 天前
Qt5-雷达项目
开发语言·qt
肩上风骋1 天前
QT实现列表通过向上向下翻页按钮翻页,以及上下键逐行显示文本行,向左向右键翻页功能
qt·按键翻页
今人不见古时月,今月曾经照古人1 天前
qt 之 QDockWidget设置不可拖动
开发语言·qt
无畏烧风1 天前
[Qt] Qt删除文本文件中的某一行
qt