#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(¤tLogFile);
// 写入当前日期时间、事件类型和文件路径信息到日志文件
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"
|