C++文件体系操作5 - 跨平台列出指定目录下的所有文件和文件夹 ...

打印 上一主题 下一主题

主题 887|帖子 887|积分 2661

1. 关键词

C++ 文件体系操作 列出指定目录下的所有文件 列出指定目录下的所有文件夹 跨平台
2. fileutil.h
  1. #pragma once
  2. #include <string>
  3. #include <cstdio>
  4. #include <cstdint>
  5. #include "filetype.h"
  6. #include "filepath.h"
  7. namespace cutl
  8. {
  9.     /**
  10.      * @brief The file guard class to manage the FILE pointer automatically.
  11.      * file_guard object can close the FILE pointer automatically when his scope is exit.
  12.      */
  13.     class file_guard
  14.     {
  15.     public:
  16.         /**
  17.          * @brief Construct a new file guard object
  18.          *
  19.          * @param file the pointer of the FILE object
  20.          */
  21.         explicit file_guard(FILE *file);
  22.         /**
  23.          * @brief Destroy the file guard object
  24.          *
  25.          */
  26.         ~file_guard();
  27.         /**
  28.          * @brief Get the FILE pointer.
  29.          *
  30.          * @return FILE*
  31.          */
  32.         FILE *getfd() const;
  33.     private:
  34.         FILE *file_;
  35.     };
  36.     /**
  37.      * @brief List all files in a directory.
  38.      *
  39.      * @param dirpath the filepath of the directory to be listed
  40.      * @param type file type to be listed, default is all types.
  41.      * @param recursive whether to list the whole directory recursively, default is false.
  42.      * If true, means list the whole directory recursively, like the 'ls -R' command.
  43.      * @return filevec the vector of file_entity, filepaths in the directory.
  44.      */
  45.     filevec list_files(const filepath &dirpath, filetype type = filetype::all, bool recursive = false);
  46. } // namespace cutl
复制代码
3. fileutil.cpp
  1. #include <cstdio>
  2. #include <map>
  3. #include <iostream>
  4. #include <cstring>
  5. #include <sys/stat.h>
  6. #include "fileutil.h"
  7. #include "inner/logger.h"
  8. #include "inner/filesystem.h"
  9. #include "strutil.h"
  10. namespace cutl
  11. {
  12.     file_guard::file_guard(FILE *file)
  13.         : file_(file)
  14.     {
  15.     }
  16.     file_guard::~file_guard()
  17.     {
  18.         if (file_)
  19.         {
  20.             // CUTL_DEBUG("close file");
  21.             int ret = fclose(file_);
  22.             if (ret != 0)
  23.             {
  24.                 CUTL_ERROR("fail to close file, ret" + std::to_string(ret));
  25.             }
  26.             file_ = nullptr;
  27.         }
  28.         // ROBOLOG_DCHECK(file_ == nullptr);
  29.     }
  30.     FILE *file_guard::getfd() const
  31.     {
  32.         return file_;
  33.     }
  34.     filevec list_files(const filepath &dirpath, filetype type, bool recursive)
  35.     {
  36.         return list_sub_files(dirpath.str(), type, recursive);
  37.     }
复制代码
4. filesystem_win.h
  1. #include <vector>
  2. #include <string>
  3. #pragma once
  4. namespace cutl
  5. {
  6.     filetype get_file_type(const std::string &filepath);
  7.     filevec list_sub_files(const std::string &dirpath, filetype type = filetype::all, bool recursive = false);
  8. } // namespace cutl
复制代码
5. filesystem_win.cpp
  1. #if defined(_WIN32) || defined(__WIN32__)
  2. #include <io.h>
  3. #include <direct.h>
  4. #include <Windows.h>
  5. #include <stdlib.h>
  6. #include "strutil.h"
  7. #include "filesystem.h"
  8. #include "logger.h"
  9. namespace cutl
  10. {
  11.     filetype get_file_type(DWORD attributes, const std::string &extension)
  12.     {
  13.         filetype type = filetype::unknown;
  14.         if (attributes == INVALID_FILE_ATTRIBUTES)
  15.         {
  16.             CUTL_WARN("Failed to get file attributes, error code: " + std::to_string(GetLastError()));
  17.             if (extension == ".lnk")
  18.             {
  19.                 // 注意:测试时发现,有些快捷方式访问会失败,用后缀名判断进行兜底
  20.                 type = filetype::symlink;
  21.             }
  22.             return type;
  23.         }
  24.         else
  25.         {
  26.             if (attributes & FILE_ATTRIBUTE_DIRECTORY)
  27.             {
  28.                 type = filetype::directory; // directory
  29.             }
  30.             else if (attributes & FILE_ATTRIBUTE_NORMAL || attributes & FILE_ATTRIBUTE_READONLY)
  31.             {
  32.                 // 普通文件|只读文件
  33.                 type = filetype::file; // regular file
  34.             }
  35.             else if ((attributes & FILE_ATTRIBUTE_ARCHIVE) && extension == ".lnk")
  36.             {
  37.                 // windows的快捷方式
  38.                 type = filetype::symlink; // symbolic link
  39.             }
  40.         }
  41.         return type;
  42.     }
  43.     std::string get_file_extension(const std::string &filepath)
  44.     {
  45.         auto pos = filepath.find_last_of('.');
  46.         std::string extension = "";
  47.         if (pos != std::string::npos)
  48.         {
  49.             extension = filepath.substr(pos);
  50.             extension = cutl::to_lower(extension);
  51.         }
  52.         return extension;
  53.     }
  54.     // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesa
  55.     // https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
  56.     filetype get_file_type(const std::string &filepath)
  57.     {
  58.         auto attributes = GetFileAttributesA(filepath.c_str());
  59.         auto extension = get_file_extension(filepath);
  60.         // CUTL_DEBUG(filepath + ", extension: " + extension + ", attributes: " + std::to_string(attributes));
  61.         return get_file_type(attributes, extension);
  62.     }
  63.     filevec list_sub_files(const std::string &dirpath, filetype type, bool recursive)
  64.     {
  65.         filevec file_list;
  66.         // 使用FindFirstFileA查找第一个文件
  67.         auto findpath = dirpath + win_separator + "*.*";
  68.         WIN32_FIND_DATAA findData = {0};
  69.         HANDLE hFind = FindFirstFileA(findpath.c_str(), &findData);
  70.         if (hFind == INVALID_HANDLE_VALUE || hFind == NULL)
  71.         {
  72.             CUTL_ERROR("FindFirstFileA failed for " + findpath + ", errCode: " + std::to_string(GetLastError()));
  73.             return file_list;
  74.         }
  75.         do
  76.         {
  77.             auto dwAttrs = findData.dwFileAttributes;
  78.             auto filename = std::string(findData.cFileName);
  79.             CUTL_DEBUG(filename + ", attributes: " + std::to_string(dwAttrs));
  80.             if (is_special_dir(filename))
  81.             {
  82.                 // “..”和“.”不做处理
  83.                 continue;
  84.             }
  85.             std::string filepath = dirpath + win_separator + filename;
  86.             auto extension = get_file_extension(filename);
  87.             auto ftype = get_file_type(dwAttrs, extension);
  88.             if (ftype & type)
  89.             {
  90.                 file_entity entity;
  91.                 entity.type = ftype;
  92.                 entity.filepath = filepath;
  93.                 file_list.emplace_back(entity);
  94.             }
  95.             if ((dwAttrs & FILE_ATTRIBUTE_DIRECTORY) && recursive)
  96.             {
  97.                 // directory
  98.                 auto sub_files = list_sub_files(filepath, type, recursive);
  99.                 if (!sub_files.empty())
  100.                 {
  101.                     file_list.insert(file_list.end(), sub_files.begin(), sub_files.end());
  102.                 }
  103.             }
  104.         } while (FindNextFileA(hFind, &findData));
  105.         // 关闭句柄
  106.         FindClose(hFind);
  107.         return file_list;
  108.     }
  109. } // namespace cutl
  110. #endif // defined(_WIN32) || defined(__WIN32__)
复制代码
6. filesystem_unix.cpp
  1. #if defined(_WIN32) || defined(__WIN32__)
  2. // do nothing
  3. #else
  4. #include <unistd.h>
  5. #include <sys/stat.h>
  6. #include <dirent.h>
  7. #include <stack>
  8. #include <cstring>
  9. #include <utime.h>
  10. #include <stdlib.h>
  11. #include <sys/time.h>
  12. #include "filesystem.h"
  13. #include "inner/logger.h"
  14. namespace cutl
  15. {
  16.     filetype get_file_type(const std::string &filepath)
  17.     {
  18.         struct stat file_stat;
  19.         int ret = lstat(filepath.c_str(), &file_stat);
  20.         if (0 != ret)
  21.         {
  22.             CUTL_ERROR("stat error. filepath:" + filepath + ", error:" + strerror(errno));
  23.             return filetype::unknown;
  24.         }
  25.         return get_file_type(file_stat.st_mode);
  26.     }
  27.     filevec list_sub_files(const std::string &dirpath, filetype type, bool recursive)
  28.     {
  29.         filevec file_list;
  30.         DIR *dir = opendir(dirpath.c_str()); // 打开这个目录
  31.         if (dir == NULL)
  32.         {
  33.             CUTL_ERROR("opendir error. dirpath:" + dirpath + ", error:" + strerror(errno));
  34.             return file_list;
  35.         }
  36.         struct dirent *file_info = NULL;
  37.         // 逐个读取目录中的文件到file_info
  38.         while ((file_info = readdir(dir)) != NULL)
  39.         {
  40.             // 系统有个系统文件,名为“..”和“.”,对它不做处理
  41.             std::string filename(file_info->d_name);
  42.             if (is_special_dir(filename))
  43.             {
  44.                 continue;
  45.             }
  46.             struct stat file_stat; // 文件的信息
  47.             std::string filepath = dirpath + unix_separator + filename;
  48.             int ret = lstat(filepath.c_str(), &file_stat);
  49.             if (0 != ret)
  50.             {
  51.                 CUTL_ERROR("stat error. filepath:" + filepath + ", error:" + strerror(errno));
  52.                 closedir(dir);
  53.                 return file_list;
  54.             }
  55.             auto ftype = get_file_type(file_stat.st_mode);
  56.             if (ftype & type)
  57.             {
  58.                 file_entity entity;
  59.                 entity.type = ftype;
  60.                 entity.filepath = filepath;
  61.                 file_list.emplace_back(entity);
  62.             }
  63.             if (S_ISDIR(file_stat.st_mode) && recursive)
  64.             {
  65.                 auto sub_files = list_sub_files(filepath, type, recursive);
  66.                 if (!sub_files.empty())
  67.                 {
  68.                     file_list.insert(file_list.end(), sub_files.begin(), sub_files.end());
  69.                 }
  70.             }
  71.         }
  72.         closedir(dir);
  73.         return file_list;
  74.     }
  75. } // namespace cutl
  76. #endif // defined(_WIN32) || defined(__WIN32__)
复制代码
7. 源码地点

更多详细代码,请检察本人写的C++ 通用工具库: common_util, 本项目已开源,代码简洁,且有详细的文档和Demo。
【SunLogging】
扫码二维码,关注微信公众号,阅读更多出色内容
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

愛在花開的季節

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表