C++实现的工具类,用于遍历指定路径并查找包含指定扩展名文件(如.shp.zip)的文件夹路径。该实现使用C++17的<filesystem>库,确保跨平台兼容性。

#include <iostream>
#include <vector>
#include <string>
#include <filesystem>
#include <algorithm>
#include <cctype>

namespace fs = std::filesystem;

class FileFolderFinder {
public:
    /**
     * 查找指定路径下包含指定扩展名文件的文件夹路径
     * 
     * @param rootPath 根目录路径
     * @param extension 要搜索的文件扩展名(如".shp"或"shp")
     * @return 包含指定扩展名文件的文件夹路径列表
     */
    static std::vector<std::string> findFoldersWithExtension(const std::string& rootPath, const std::string& extension) {
        // 自动添加扩展名前的点(如果用户忘记添加)
        std::string normalizedExtension = extension;
        if (!normalizedExtension.empty() && normalizedExtension[0] != '.') {
            normalizedExtension = "." + normalizedExtension;
        }
        // 转换为小写用于大小写不敏感比较
        std::transform(normalizedExtension.begin(), normalizedExtension.end(), 
                      normalizedExtension.begin(), ::tolower);
        std::vector<std::string> result;
        // 检查根目录是否存在
        if (!fs::exists(rootPath) || !fs::is_directory(rootPath)) {
            throw std::invalid_argument("Invalid directory: " + rootPath);
        }
        // 递归遍历目录
        findFoldersWithExtensionRecursive(fs::path(rootPath), normalizedExtension, result);
        return result;
    }

private:
    /**
     * 递归查找包含指定扩展名文件的文件夹
     */
    static void findFoldersWithExtensionRecursive(
        const fs::path& directory, 
        const std::string& extension, 
        std::vector<std::string>& result
    ) {
        // 检查当前目录是否包含指定扩展名的文件
        if (hasFileWithExtension(directory, extension)) {
            result.push_back(directory.string());
        }
        
        // 遍历子目录
        for (const auto& entry : fs::directory_iterator(directory)) {
            if (fs::is_directory(entry)) {
                findFoldersWithExtensionRecursive(entry.path(), extension, result);
            }
        }
    }
    
    /**
     * 检查文件夹是否包含指定扩展名的文件
     */
    static bool hasFileWithExtension(const fs::path& directory, const std::string& extension) {
        for (const auto& entry : fs::directory_iterator(directory)) {
            if (fs::is_regular_file(entry) && 
                hasExtension(entry.path().filename().string(), extension)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 检查文件名是否以指定扩展名结尾(大小写不敏感)
     */
    static bool hasExtension(const std::string& filename, const std::string& extension) {
        // 转换文件名和扩展名为小写
        std::string lowerFilename = filename;
        std::string lowerExtension = extension;
        std::transform(lowerFilename.begin(), lowerFilename.end(), lowerFilename.begin(), ::tolower);
        std::transform(lowerExtension.begin(), lowerExtension.end(), lowerExtension.begin(), ::tolower);
        
        // 检查是否以扩展名结尾
        return lowerFilename.size() >= lowerExtension.size() &&
               lowerFilename.compare(lowerFilename.size() - lowerExtension.size(), 
                                    lowerExtension.size(), lowerExtension) == 0;
    }
};

// 使用示例
int main() {
    try {
        // 搜索.shp文件所在文件夹
        auto shpFolders = FileFolderFinder::findFoldersWithExtension(
            "C:/GIS_Data", 
            ".shp"  // 或 "shp"
        );
        
        std::cout << "包含.shp文件的文件夹路径:\n";
        for (const auto& folder : shpFolders) {
            std::cout << folder << "\n";
        }
        
        // 搜索.zip文件所在文件夹
        auto zipFolders = FileFolderFinder::findFoldersWithExtension(
            "C:/Archive", 
            ".zip"  // 或 "zip"
        );
        
        std::cout << "\n包含.zip文件的文件夹路径:\n";
        for (const auto& folder : zipFolders) {
            std::cout << folder << "\n";
        }
        
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}

关键特性说明

  1. 自动处理扩展名格式
    • 支持传入.shpshp两种形式
    • 自动添加点前缀(shp.shp
    • 大小写不敏感匹配(.SHP.Shp.shp 都会被识别)
  2. 跨平台支持
    • 使用C++17的<filesystem>
    • 适用于Windows、Linux和macOS
    • 自动处理不同平台的路径分隔符
  3. 健壮性处理
    • 检查根目录是否存在
    • 处理异常情况(抛出std::invalid_argument
    • 递归遍历所有子目录
  4. 性能优化
    • 仅检查文件(不检查目录)
    • 递归遍历时跳过非目录项
    • 使用小写比较避免大小写问题

使用说明

  1. 编译要求

    • C++17标准(编译时需添加-std=c++17
    • 在Windows上可能需要链接shlwapi.lib(如果使用MSVC)
  2. 编译命令示例

    # Linux/macOS
    g++ -std=c++17 file_finder.cpp -o file_finder
    
    # Windows (MSVC)
    cl /std:c++17 file_finder.cpp
    
  3. 使用示例

    // 搜索.shp文件
    auto shpFolders = FileFolderFinder::findFoldersWithExtension("C:/data", "shp");
    
    // 搜索.zip文件
    auto zipFolders = FileFolderFinder::findFoldersWithExtension("C:/archive", ".zip");
    

输出示例

假设目录结构:

C:/
└── GIS_Data/
    ├── Project1/
    │   ├── data.shp
    │   └── metadata.txt
    ├── Project2/
    │   └── data.zip
    └── Project3/
        ├── map.shp
        └── report.pdf

程序将输出:

包含.shp文件的文件夹路径:
C:/GIS_Data/Project1
C:/GIS_Data/Project3

包含.zip文件的文件夹路径:
C:/GIS_Data/Project2

注意事项

  1. 路径格式
    • 在Windows上推荐使用C:/GIS_Data(正斜杠)或C:\\GIS_Data(双反斜杠)
    • 在Linux/macOS上使用/home/user/data
  2. 扩展名处理
    • 传入扩展名时,建议使用小写(如.shp)但程序会自动转换
    • 不需要在扩展名前加点(程序会自动添加)
  3. 错误处理
    • 如果根目录不存在,会抛出std::invalid_argument
    • 可以捕获异常进行错误处理
  4. 性能考虑
    • 对于大型目录结构,递归遍历可能较慢
    • 如需优化,可以添加最大深度参数或使用并行遍历

可以灵活地搜索.shp.zip或其他任何文件类型所在文件夹路径。