C++文件系统操作5 - 跨平台列出指定目录下的所有文件和文件夹
1. 关键词 C++ 文件系统操作 列出指定目录下的所有文件 列出指定目录下的所有文件夹 跨平台
2. fileutil.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #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 1 2 3 4 5 6 7 8 9 10 11 #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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 #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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 #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。