1. 关键词
C++ 文件系统操作 列出指定目录下的所有文件 列出指定目录下的所有文件夹 跨平台
2. fileutil.h
| |
| #pragma once |
| |
| #include <string> |
| #include <cstdio> |
| #include <cstdint> |
| #include "filetype.h" |
| #include "filepath.h" |
| |
| namespace cutl |
| { |
| |
| |
| |
| |
| |
| class file_guard |
| { |
| public: |
| |
| |
| |
| |
| |
| explicit file_guard(FILE *file); |
| |
| |
| |
| |
| |
| ~file_guard(); |
| |
| |
| |
| |
| |
| |
| FILE *getfd() const; |
| |
| private: |
| FILE *file_; |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| filevec list_files(const filepath &dirpath, filetype type = filetype::all, bool recursive = false); |
| |
| } |
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_) |
| { |
| |
| int ret = fclose(file_); |
| if (ret != 0) |
| { |
| CUTL_ERROR("fail to close file, ret" + std::to_string(ret)); |
| } |
| 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); |
| } |
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; |
| } |
| else if (attributes & FILE_ATTRIBUTE_NORMAL || attributes & FILE_ATTRIBUTE_READONLY) |
| { |
| |
| type = filetype::file; |
| } |
| else if ((attributes & FILE_ATTRIBUTE_ARCHIVE) && extension == ".lnk") |
| { |
| |
| type = filetype::symlink; |
| } |
| } |
| |
| 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; |
| } |
| |
| |
| |
| filetype get_file_type(const std::string &filepath) |
| { |
| auto attributes = GetFileAttributesA(filepath.c_str()); |
| auto extension = get_file_extension(filepath); |
| |
| return get_file_type(attributes, extension); |
| } |
| |
| filevec list_sub_files(const std::string &dirpath, filetype type, bool recursive) |
| { |
| filevec file_list; |
| |
| |
| 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) |
| { |
| |
| 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; |
| } |
| } |
| |
| #endif |
6. filesystem_unix.cpp
| #if defined(_WIN32) || defined(__WIN32__) |
| |
| #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; |
| |
| 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; |
| } |
| } |
| |
| #endif |
7. 源码地址
更多详细代码,请查看本人写的C++ 通用工具库: common_util, 本项目已开源,代码简洁,且有详细的文档和Demo。
【SunLogging】
扫码二维码,关注微信公众号,阅读更多精彩内容
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战