You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 23:35:35