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

SSD环境下C++文件搜索程序的性能优化咨询

C++文件搜索程序优化求助

我写了一个C++文件搜索程序,现在遇到两个问题:一是搜索速度极慢,比如搜索视频文件耗时达94秒;二是结果中出现大量重复路径。我使用SSD存储(总容量465GB,已占用279GB),Visual Studio已开启最高速度优化(/O2),改写代码后性能无明显提升,现寻求加速及修复重复问题的方案。

核心搜索函数

void searchFiles(const std::string& searchQuery, const std::string& rootDir, std::vector<std::string>& results) {
    std::queue<fs::path> dirs;
    dirs.push(rootDir);

    while (!dirs.empty()) {
        fs::path currentDir = dirs.front();
        dirs.pop();

        try {
            for (const auto& entry : fs::directory_iterator(currentDir)) {
                if (fs::is_directory(entry)) {
                    dirs.push(entry.path());
                }
                else {
                    if (entry.path().filename().string().find(searchQuery) != std::string::npos) {
                        results.push_back(entry.path().string());
                    }
                }
            }
        }
        catch (const std::exception& e) { }
    }
}

调用代码

void ScannerFile::ScanningFile()
{
    for (size_t i = 0; i < defaultPath.size(); i++)
    {
        searchFiles(defaultPath[i], "C:\\", ModuleManager::resultFile);
    }
}

测试结果示例

C:\Users\mgrr\Videos\Desktop\Desktop 2024.10.20 - 16.03.16.04.mp4
C:\Users\mgrr\AppData\Roaming\Microsoft\Windows\Recent\Desktop 2024.10.20 - 16.03.16.04.lnk
C:\Users\mgrr\Videos\Desktop\Desktop 2024.10.20 - 16.03.16.04.mp4
C:\Users\mgrr\AppData\Roaming\Microsoft\Windows\Recent\Desktop 2024.10.20 - 16.03.16.04.lnk
C:\Users\mgrr\Videos\Desktop\Desktop 2024.10.20 - 16.03.16.04.mp4
C:\Users\mgrr\AppData\Roaming\Microsoft\Windows\Recent\Desktop 2024.10.20 - 16.03.16.04.lnk

Execution time: 94.0131 seconds

优化方案

1. 修复重复结果问题

重复的根源是调用逻辑错误:你循环多次调用searchFiles,每次都从C:\根目录全量搜索,且所有结果都写入同一个全局向量ModuleManager::resultFile,导致同一文件被多次添加。

解决办法

将多查询合并为单次目录遍历,避免重复扫描:

void ScannerFile::ScanningFile()
{
    ModuleManager::resultFile.clear(); // 先清空旧结果
    std::queue<fs::path> dirs;
    dirs.push("C:\\");

    while (!dirs.empty()) {
        fs::path currentDir = dirs.front();
        dirs.pop();

        try {
            for (const auto& entry : fs::directory_iterator(currentDir)) {
                if (fs::is_directory(entry)) {
                    dirs.push(entry.path());
                }
                else {
                    const std::string filename = entry.path().filename().string();
                    // 一次性匹配所有查询条件
                    for (const auto& query : defaultPath) {
                        if (filename.find(query) != std::string::npos) {
                            ModuleManager::resultFile.push_back(entry.path().string());
                            break; // 匹配到一个条件就停止检查
                        }
                    }
                }
            }
        }
        catch (const std::exception& e) { }
    }
}

2. 性能加速优化

(1)减少字符串转换开销

entry.path().filename().string()会频繁生成临时字符串,改用C++20的fs::path::contains方法直接匹配,或缓存字符串减少重复转换:

// C++20及以上推荐用法,避免string转换
if (entry.path().filename().contains(searchQuery)) {
    results.push_back(entry.path().string());
}

// 旧标准缓存字符串写法
const std::string filename = entry.path().filename().string();
if (filename.find(searchQuery) != std::string::npos) {
    results.push_back(entry.path().string());
}

(2)并行遍历目录

SSD支持并行IO,单线程遍历会浪费性能,用多线程处理子目录:

#include <future>
#include <mutex>

void searchFilesRecursive(const std::string& searchQuery, const fs::path& currentDir, 
                          std::vector<std::string>& results, std::mutex& mtx) {
    try {
        std::vector<std::future<void>> futures;
        for (const auto& entry : fs::directory_iterator(currentDir)) {
            if (fs::is_directory(entry)) {
                // 异步处理子目录
                futures.emplace_back(std::async(std::launch::async, 
                    &searchFilesRecursive, std::ref(searchQuery), entry.path(), 
                    std::ref(results), std::ref(mtx)));
            }
            else {
                if (entry.path().filename().contains(searchQuery)) {
                    std::lock_guard<std::mutex> lock(mtx);
                    results.push_back(entry.path().string());
                }
            }
        }
        // 等待所有子线程完成
        for (auto& f : futures) f.get();
    }
    catch (const std::exception& e) { }
}

void searchFiles(const std::string& searchQuery, const std::string& rootDir, std::vector<std::string>& results) {
    std::mutex mtx;
    searchFilesRecursive(searchQuery, rootDir, results, mtx);
}

(3)跳过无关目录

提前过滤系统目录、缓存目录等无需搜索的路径,减少遍历量:

const std::unordered_set<std::string> skip_dirs = {
    "Windows", "System Volume Information", "AppData\\Local\\Temp", 
    "Program Files", "Program Files (x86)"
};

// 判断目录时跳过指定路径
if (fs::is_directory(entry)) {
    std::string dir_name = entry.path().filename().string();
    if (skip_dirs.find(dir_name) == skip_dirs.end()) {
        dirs.push(entry.path());
    }
}

(4)预分配结果向量空间

提前预估结果数量,用reserve预分配内存,避免push_back频繁扩容:

// 在搜索前调用,比如预估最多10000个结果
results.reserve(10000);

(5)改用Windows原生API遍历

标准库fs::directory_iterator在Windows平台的性能不如原生FindFirstFileW/FindNextFileW,以下是简化示例:

#include <windows.h>

void searchFilesWinAPI(const std::wstring& searchQuery, const std::wstring& rootDir, 
                       std::vector<std::wstring>& results) {
    WIN32_FIND_DATAW findData;
    HANDLE hFind = FindFirstFileW((rootDir + L"\\*").c_str(), &findData);
    if (hFind == INVALID_HANDLE_VALUE) return;

    do {
        if (wcscmp(findData.cFileName, L".") == 0 || wcscmp(findData.cFileName, L"..") == 0) continue;

        std::wstring fullPath = rootDir + L"\\" + findData.cFileName;
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            searchFilesWinAPI(searchQuery, fullPath, results);
        } else {
            if (std::wstring(findData.cFileName).find(searchQuery) != std::wstring::npos) {
                results.push_back(fullPath);
            }
        }
    } while (FindNextFileW(hFind, &findData));

    FindClose(hFind);
}

3. 其他实用建议

  • 优先搜索用户目录(如C:\Users)而非全盘遍历,除非必须;
  • 缓存搜索结果,相同查询直接返回缓存;
  • 按后缀名搜索时,直接匹配entry.path().extension()比find更高效,例如entry.path().extension() == ".mp4"。

内容的提问来源于stack exchange,提问作者cold vinar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 20:40:54