1. 关键词
C++ 文件体系操作 列出指定目录下的所有文件 列出指定目录下的所有文件夹 跨平台
2. fileutil.h
- #pragma once
- #include <string>
- #include <cstdio>
- #include <cstdint>
- #include "filetype.h"
- #include "filepath.h"
- namespace cutl
- {
- /**
- * @brief The file guard class to manage the FILE pointer automatically.
- * file_guard object can close the FILE pointer automatically when his scope is exit.
- */
- class file_guard
- {
- public:
- /**
- * @brief Construct a new file guard object
- *
- * @param file the pointer of the FILE object
- */
- explicit file_guard(FILE *file);
- /**
- * @brief Destroy the file guard object
- *
- */
- ~file_guard();
- /**
- * @brief Get the FILE pointer.
- *
- * @return FILE*
- */
- FILE *getfd() const;
- private:
- FILE *file_;
- };
- /**
- * @brief List all files in a directory.
- *
- * @param dirpath the filepath of the directory to be listed
- * @param type file type to be listed, default is all types.
- * @param recursive whether to list the whole directory recursively, default is false.
- * If true, means list the whole directory recursively, like the 'ls -R' command.
- * @return filevec the vector of file_entity, filepaths in the directory.
- */
- filevec list_files(const filepath &dirpath, filetype type = filetype::all, bool recursive = false);
- } // namespace cutl
复制代码 3. fileutil.cpp
- #include <cstdio>
- #include <map>
- #include <iostream>
- #include <cstring>
- #include <sys/stat.h>
- #include "fileutil.h"
- #include "inner/logger.h"
- #include "inner/filesystem.h"
- #include "strutil.h"
- namespace cutl
- {
- file_guard::file_guard(FILE *file)
- : file_(file)
- {
- }
- file_guard::~file_guard()
- {
- if (file_)
- {
- // CUTL_DEBUG("close file");
- int ret = fclose(file_);
- if (ret != 0)
- {
- CUTL_ERROR("fail to close file, ret" + std::to_string(ret));
- }
- file_ = nullptr;
- }
- // ROBOLOG_DCHECK(file_ == nullptr);
- }
- FILE *file_guard::getfd() const
- {
- return file_;
- }
- filevec list_files(const filepath &dirpath, filetype type, bool recursive)
- {
- return list_sub_files(dirpath.str(), type, recursive);
- }
复制代码 4. filesystem_win.h
- #include <vector>
- #include <string>
- #pragma once
- namespace cutl
- {
- filetype get_file_type(const std::string &filepath);
- filevec list_sub_files(const std::string &dirpath, filetype type = filetype::all, bool recursive = false);
- } // namespace cutl
复制代码 5. filesystem_win.cpp
- #if defined(_WIN32) || defined(__WIN32__)
- #include <io.h>
- #include <direct.h>
- #include <Windows.h>
- #include <stdlib.h>
- #include "strutil.h"
- #include "filesystem.h"
- #include "logger.h"
- namespace cutl
- {
- filetype get_file_type(DWORD attributes, const std::string &extension)
- {
- filetype type = filetype::unknown;
- if (attributes == INVALID_FILE_ATTRIBUTES)
- {
- CUTL_WARN("Failed to get file attributes, error code: " + std::to_string(GetLastError()));
- if (extension == ".lnk")
- {
- // 注意:测试时发现,有些快捷方式访问会失败,用后缀名判断进行兜底
- type = filetype::symlink;
- }
- return type;
- }
- else
- {
- if (attributes & FILE_ATTRIBUTE_DIRECTORY)
- {
- type = filetype::directory; // directory
- }
- else if (attributes & FILE_ATTRIBUTE_NORMAL || attributes & FILE_ATTRIBUTE_READONLY)
- {
- // 普通文件|只读文件
- type = filetype::file; // regular file
- }
- else if ((attributes & FILE_ATTRIBUTE_ARCHIVE) && extension == ".lnk")
- {
- // windows的快捷方式
- type = filetype::symlink; // symbolic link
- }
- }
- return type;
- }
- std::string get_file_extension(const std::string &filepath)
- {
- auto pos = filepath.find_last_of('.');
- std::string extension = "";
- if (pos != std::string::npos)
- {
- extension = filepath.substr(pos);
- extension = cutl::to_lower(extension);
- }
- return extension;
- }
- // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesa
- // https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
- filetype get_file_type(const std::string &filepath)
- {
- auto attributes = GetFileAttributesA(filepath.c_str());
- auto extension = get_file_extension(filepath);
- // CUTL_DEBUG(filepath + ", extension: " + extension + ", attributes: " + std::to_string(attributes));
- return get_file_type(attributes, extension);
- }
- filevec list_sub_files(const std::string &dirpath, filetype type, bool recursive)
- {
- filevec file_list;
- // 使用FindFirstFileA查找第一个文件
- auto findpath = dirpath + win_separator + "*.*";
- WIN32_FIND_DATAA findData = {0};
- HANDLE hFind = FindFirstFileA(findpath.c_str(), &findData);
- if (hFind == INVALID_HANDLE_VALUE || hFind == NULL)
- {
- CUTL_ERROR("FindFirstFileA failed for " + findpath + ", errCode: " + std::to_string(GetLastError()));
- return file_list;
- }
- do
- {
- auto dwAttrs = findData.dwFileAttributes;
- auto filename = std::string(findData.cFileName);
- CUTL_DEBUG(filename + ", attributes: " + std::to_string(dwAttrs));
- if (is_special_dir(filename))
- {
- // “..”和“.”不做处理
- continue;
- }
- std::string filepath = dirpath + win_separator + filename;
- auto extension = get_file_extension(filename);
- auto ftype = get_file_type(dwAttrs, extension);
- if (ftype & type)
- {
- file_entity entity;
- entity.type = ftype;
- entity.filepath = filepath;
- file_list.emplace_back(entity);
- }
- if ((dwAttrs & FILE_ATTRIBUTE_DIRECTORY) && recursive)
- {
- // directory
- auto sub_files = list_sub_files(filepath, type, recursive);
- if (!sub_files.empty())
- {
- file_list.insert(file_list.end(), sub_files.begin(), sub_files.end());
- }
- }
- } while (FindNextFileA(hFind, &findData));
- // 关闭句柄
- FindClose(hFind);
- return file_list;
- }
- } // namespace cutl
- #endif // defined(_WIN32) || defined(__WIN32__)
复制代码 6. filesystem_unix.cpp
- #if defined(_WIN32) || defined(__WIN32__)
- // do nothing
- #else
- #include <unistd.h>
- #include <sys/stat.h>
- #include <dirent.h>
- #include <stack>
- #include <cstring>
- #include <utime.h>
- #include <stdlib.h>
- #include <sys/time.h>
- #include "filesystem.h"
- #include "inner/logger.h"
- namespace cutl
- {
- filetype get_file_type(const std::string &filepath)
- {
- struct stat file_stat;
- int ret = lstat(filepath.c_str(), &file_stat);
- if (0 != ret)
- {
- CUTL_ERROR("stat error. filepath:" + filepath + ", error:" + strerror(errno));
- return filetype::unknown;
- }
- return get_file_type(file_stat.st_mode);
- }
- filevec list_sub_files(const std::string &dirpath, filetype type, bool recursive)
- {
- filevec file_list;
- DIR *dir = opendir(dirpath.c_str()); // 打开这个目录
- if (dir == NULL)
- {
- CUTL_ERROR("opendir error. dirpath:" + dirpath + ", error:" + strerror(errno));
- return file_list;
- }
- struct dirent *file_info = NULL;
- // 逐个读取目录中的文件到file_info
- while ((file_info = readdir(dir)) != NULL)
- {
- // 系统有个系统文件,名为“..”和“.”,对它不做处理
- std::string filename(file_info->d_name);
- if (is_special_dir(filename))
- {
- continue;
- }
- struct stat file_stat; // 文件的信息
- std::string filepath = dirpath + unix_separator + filename;
- int ret = lstat(filepath.c_str(), &file_stat);
- if (0 != ret)
- {
- CUTL_ERROR("stat error. filepath:" + filepath + ", error:" + strerror(errno));
- closedir(dir);
- return file_list;
- }
- auto ftype = get_file_type(file_stat.st_mode);
- if (ftype & type)
- {
- file_entity entity;
- entity.type = ftype;
- entity.filepath = filepath;
- file_list.emplace_back(entity);
- }
- if (S_ISDIR(file_stat.st_mode) && recursive)
- {
- auto sub_files = list_sub_files(filepath, type, recursive);
- if (!sub_files.empty())
- {
- file_list.insert(file_list.end(), sub_files.begin(), sub_files.end());
- }
- }
- }
- closedir(dir);
- return file_list;
- }
- } // namespace cutl
- #endif // defined(_WIN32) || defined(__WIN32__)
复制代码 7. 源码地点
更多详细代码,请检察本人写的C++ 通用工具库: common_util, 本项目已开源,代码简洁,且有详细的文档和Demo。
【SunLogging】扫码二维码,关注微信公众号,阅读更多出色内容
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |