QThread停止与续跑问题:杀毒扫描线程中断后无法续扫
续扫功能实现方案
核心思路
扫描中断时保存当前的扫描进度(已完成的目录、当前处理的目录及剩余未扫描文件),下次启动扫描且路径未变更时,跳过已扫描内容,直接从断点位置继续执行扫描逻辑。
具体实现步骤
1. 在ScanThread类中添加断点记录变量
// ScanThread.h class ScanThread : public QThread { Q_OBJECT private: // 原有变量 bool m_requestedStop; QString m_scanPath; // 新增断点相关变量 QQueue<QString> m_pendingDirs; // 待扫描的目录队列(替代递归,方便保存进度) QString m_currentProcessingDir; // 中断时正在处理的目录 QList<QFileInfo> m_remainingFiles; // 当前目录中未完成扫描的文件列表 bool m_isResuming; // 是否启用续扫模式 };
2. 改造扫描逻辑,加入续扫判断
// ScanThread.cpp void ScanThread::run() { if (m_isResuming) { // 续扫:先处理当前目录剩余文件 processRemainingFiles(); // 继续处理待扫描目录队列中的剩余目录 processPendingDirs(); } else { // 全新扫描:重置所有断点变量,初始化扫描队列 resetBreakpointData(); m_pendingDirs.enqueue(m_scanPath); processPendingDirs(); } } // 处理当前目录剩余文件 void ScanThread::processRemainingFiles() { for (int i = 0; i < m_remainingFiles.size(); ++i) { if (m_requestedStop) { // 更新剩余文件列表为当前索引之后的内容 m_remainingFiles = m_remainingFiles.mid(i); return; } QFileInfo file = m_remainingFiles[i]; // 执行文件扫描逻辑 emit fileScanned(file); // 如果是目录,加入待扫描队列 if (file.isDir()) { m_pendingDirs.enqueue(file.absoluteFilePath()); } } m_remainingFiles.clear(); m_currentProcessingDir.clear(); } // 处理待扫描目录队列 void ScanThread::processPendingDirs() { while (!m_pendingDirs.isEmpty() && !m_requestedStop) { QString dirPath = m_pendingDirs.dequeue(); m_currentProcessingDir = dirPath; QDir dir(dirPath); QFileInfoList fileList = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); m_remainingFiles = fileList; processRemainingFiles(); } } // 重置断点数据 void ScanThread::resetBreakpointData() { m_pendingDirs.clear(); m_currentProcessingDir.clear(); m_remainingFiles.clear(); }
3. 主界面适配续扫逻辑
// MainWindow.cpp void MainWindow::on_scanBtn_clicked() { QString currentPath = ui->pathInput->text(); if (ui->scanBtn->text() == "Scan") { if (currentPath == m_lastScanPath && m_scanThread->hasValidBreakpoint()) { // 路径未变且存在有效断点,开启续扫模式 m_scanThread->setResumeMode(true); } else { // 全新扫描,重置断点 m_scanThread->setResumeMode(false); m_lastScanPath = currentPath; m_scanThread->setScanPath(currentPath); } m_scanThread->start(); ui->scanBtn->setText("Stop"); } else { // 确认终止扫描,等待线程保存断点 if (QMessageBox::question(this, "Stop Scanning", "Confirm to stop scanning?") == QMessageBox::Yes) { m_scanThread->requestStop(); m_scanThread->wait(); ui->scanBtn->setText("Scan"); } } }
4. 添加断点有效性判断方法
// ScanThread.h public: void requestStop() { m_requestedStop = true; } void setResumeMode(bool resume) { m_isResuming = resume; } void setScanPath(const QString& path) { m_scanPath = path; } bool hasValidBreakpoint() const { return !m_currentProcessingDir.isEmpty() || !m_remainingFiles.isEmpty() || !m_pendingDirs.isEmpty(); }
关键注意事项
- 线程安全:所有断点变量的读写需加
QMutex保护,避免主界面与扫描线程同时访问导致数据混乱。 - 断点持久化(可选):若需要关闭软件后保留断点,可将
m_pendingDirs、m_currentProcessingDir、m_remainingFiles序列化为JSON或二进制文件,启动时读取恢复。 - 目录遍历优化:用队列替代递归遍历,既避免栈溢出,也更方便保存待扫描的目录进度。
内容的提问来源于stack exchange,提问作者Thành Duy Cao
相关产品推荐
相关产品推荐

