C++ QT 工具日志异步分批保存
C++ QT 工具软件一般可以如此实现日志保存:
#define THREAD_ID (reinterpret_cast<qulonglong>(QThread::currentThreadId()) & 0x0FFF)
#define TIME (QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss_zzz"))
#define LOGD(msg) qDebug()<<QString("[%1] [%2] [D] [%3] %4") \
.arg(TIME)\
.arg(THREAD_ID , 4) \
.arg(QString(TAG).mid(0,20) , 20 , QChar(' ')) \
.arg((msg));
当qDebug数据更新时,将日志更新到ui界面上,
存储日志时,将日志从ui界面导出,然后存储在本地
但是存在一个问题:
主线程中存储log可能会造成线程阻塞,界面失去响应
void ClassA::on_save_clicked()
{
if (mFilePath.length() > 0)
{
QFile file(mFilePath);
if (file.open(QIODevice::WriteOnly | QIODevice::Text))
{
QTextStream stream(&file);
stream << ui->plainTextEdit->toPlainText();
}
file.close();
}
}
针对Qt中避免主线程卡死的问题,可以通过以下几种技术来避免:
-
使用多线程:将耗时的文件写入操作放在一个单独的线程中执行,这样可以避免阻塞主线程。在Qt中,可以使用
QThread
类来创建一个新线程,并在该线程中执行文件写入操作。这样可以确保主线程的响应性,不会因为长时间的文件操作而卡死。 -
异步编程:使用Qt的信号和槽机制,将文件写入操作异步化。您可以创建一个槽函数来处理文件写入,并在需要保存数据时发射一个信号,槽函数在接收到信号后异步执行文件写入操作。这样可以避免在主线程中同步执行耗时的文件操作。
-
使用TaskPool:如果您的应用是基于鸿蒙系统,可以使用系统自带的
TaskPool
多线程能力,将耗时任务交由子线程执行,避免主线程的长时间阻塞。 -
分批处理数据:类似于Linux的logcat技术,您可以将大量数据分批次写入文件,每次只处理一小部分数据,这样可以减少单次操作的时间,避免长时间的阻塞。
-
使用QCoreApplication::processEvents:在执行耗时操作时,偶尔调用
QCoreApplication::processEvents()
来处理所有挂起的事件,这样可以保持界面的响应性
eg1:
void ClassA::on_save_clicked() {
if (mFilePath.length() > 0) {
QFile file(mFilePath);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream(&file);
int batchSize = 1024 * 1024;
int totalDataSize = ui->plainTextEdit->toPlainText().length();
int offset = 0;
while (offset < totalDataSize) {
int chunkSize = qMin(batchSize, totalDataSize - offset);
QString chunk = ui->plainTextEdit->toPlainText().mid(offset, chunkSize);
stream << chunk;
offset += chunkSize;
// 处理完一批数据后,给主事件循环一些时间来处理其他事件
QCoreApplication::processEvents();
// 可以在这里添加一个简单的延时来控制写入速度,避免过于频繁
// QThread::msleep(10); // 例如,每次写入后暂停10毫秒
}
file.close();
}
}
}
eg2:
void ClassA::on_save_clicked()
{
if (mFilePath.length() > 0)
{
QtConcurrent::run([&]()
{
QFile file(mFilePath);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream(&file);
int batchSize = 1024 * 1024;
int totalDataSize = ui->plainTextEdit->toPlainText().length();
int offset = 0;
while (offset < totalDataSize) {
int chunkSize = qMin(batchSize, totalDataSize - offset);
QString chunk = ui->plainTextEdit->toPlainText().mid(offset, chunkSize);
stream << chunk;
offset += chunkSize;
}
file.close();
}
emit logSaved();
});
}
}
更好的方法是在log server接收数据时保存
实时进行Log的临时保存,然后在需要保存的时候,将文件直接move到你想要保存的地方