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_; |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| bool createdir(const filepath &path, bool recursive = false); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| bool removedir(const filepath &path, 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_; |
| } |
| |
| bool createdir(const filepath &path, bool recursive) |
| { |
| if (recursive) |
| { |
| constexpr int buf_size = MAX_PATH_LEN; |
| char buffer[buf_size] = {0}; |
| int ret = snprintf(buffer, buf_size, "%s", path.str().c_str()); |
| if (ret < 0 || ret >= buf_size) |
| { |
| CUTL_ERROR("invalid path: " + path.str()); |
| return false; |
| } |
| int len = strlen(buffer); |
| if (buffer[len - 1] != filepath::separator()) |
| { |
| buffer[len++] = filepath::separator(); |
| } |
| |
| int32_t idx = (buffer[0] == filepath::separator()) ? 1 : 0; |
| for (; idx < len; ++idx) |
| { |
| if (buffer[idx] != filepath::separator()) |
| { |
| continue; |
| } |
| buffer[idx] = '\0'; |
| filepath temp_path(buffer); |
| if (!temp_path.exists()) |
| { |
| if (!create_dir(temp_path.str())) |
| { |
| CUTL_ERROR("createdir error. dir:" + temp_path.str()); |
| return false; |
| } |
| } |
| buffer[idx] = filepath::separator(); |
| } |
| return true; |
| } |
| else |
| { |
| auto dirPath = path.dirname(); |
| if (dirPath.empty()) |
| { |
| CUTL_ERROR("invalid path: " + path.str()); |
| return false; |
| } |
| if (!cutl::path(dirPath).exists()) |
| { |
| CUTL_ERROR("directory does not exist: " + dirPath); |
| return false; |
| } |
| |
| return create_dir(path.str()); |
| } |
| } |
| |
| bool removedir(const filepath &path, bool recursive) |
| { |
| if (!path.exists()) |
| { |
| CUTL_ERROR("directory does not exist: " + path.str()); |
| return false; |
| } |
| |
| if (recursive) |
| { |
| return remove_dir_recursive(path.str()); |
| } |
| else |
| { |
| return remove_dir(path.str()); |
| } |
| } |
4. filesystem_win.h
| |
| #include <vector> |
| #include <string> |
| |
| #pragma once |
| |
| namespace cutl |
| { |
| bool create_dir(const std::string &dir_path); |
| |
| bool remove_dir(const std::string &dir_path); |
| |
| bool remove_dir_recursive(const std::string &dir_path); |
| } |
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 |
| { |
| bool create_dir(const std::string &dir_path) |
| { |
| if (_mkdir(dir_path.c_str()) != 0) |
| { |
| CUTL_ERROR("mkdir error. dir_path:" + dir_path + ", error:" + strerror(errno)); |
| return false; |
| } |
| return true; |
| } |
| |
| |
| |
| bool remove_dir(const std::string &dir_path) |
| { |
| if (_rmdir(dir_path.c_str()) != 0) |
| { |
| CUTL_ERROR("rmdir error. dir_path:" + dir_path + ", error:" + strerror(errno)); |
| return false; |
| } |
| return true; |
| } |
| |
| |
| bool remove_dir_recursive(const std::string &dir_path) |
| { |
| auto findpath = dir_path + win_separator + "*.*"; |
| WIN32_FIND_DATAA data = {0}; |
| HANDLE hFind = FindFirstFileA(findpath.c_str(), &data); |
| bool unicode = true; |
| if (hFind == INVALID_HANDLE_VALUE || hFind == NULL) |
| { |
| CUTL_ERROR("FindFirstFileA failed for " + findpath + ", errCode: " + std::to_string(GetLastError())); |
| return false; |
| } |
| |
| do |
| { |
| auto dwAttrs = data.dwFileAttributes; |
| auto filename = std::string(data.cFileName); |
| if (is_special_dir(filename)) |
| { |
| |
| continue; |
| } |
| std::string filepath = dir_path + win_separator + filename; |
| if ((dwAttrs & FILE_ATTRIBUTE_DIRECTORY)) |
| { |
| |
| if (!remove_dir_recursive(filepath)) |
| { |
| FindClose(hFind); |
| return false; |
| } |
| } |
| else |
| { |
| |
| int ret = remove(filepath.c_str()); |
| if (ret != 0) |
| { |
| CUTL_ERROR("remove " + filepath + " error, ret:" + std::to_string(ret)); |
| return false; |
| } |
| } |
| } while (FindNextFileA(hFind, &data)); |
| |
| FindClose(hFind); |
| |
| |
| if (_rmdir(dir_path.c_str()) != 0) |
| { |
| CUTL_ERROR("rmdir error. dir_path:" + dir_path + ", error:" + strerror(errno)); |
| return false; |
| } |
| |
| return true; |
| } |
| } |
| |
| #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 |
| { |
| bool create_dir(const std::string &dir_path) |
| { |
| if (mkdir(dir_path.c_str(), S_IRWXU | S_IRWXG | S_IRWXO | S_IWOTH) != 0) |
| { |
| CUTL_ERROR("mkdir error. dir_path:" + dir_path + ", error:" + strerror(errno)); |
| return false; |
| } |
| return true; |
| } |
| |
| bool remove_dir(const std::string &dir_path) |
| { |
| if (rmdir(dir_path.c_str()) != 0) |
| { |
| CUTL_ERROR("rmdir error. dir_path:" + dir_path + ", error:" + strerror(errno)); |
| return false; |
| } |
| return true; |
| } |
| |
| bool remove_dir_recursive(const std::string &dir_path) |
| { |
| DIR *dir = opendir(dir_path.c_str()); |
| if (dir == NULL) |
| { |
| CUTL_ERROR("opendir error. dir_path:" + dir_path + ", error:" + strerror(errno)); |
| return false; |
| } |
| 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 = dir_path + 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 false; |
| } |
| if (S_ISDIR(file_stat.st_mode)) |
| { |
| if (!remove_dir_recursive(filepath)) |
| { |
| closedir(dir); |
| return false; |
| } |
| } |
| else |
| { |
| int ret = remove(filepath.c_str()); |
| if (ret != 0) |
| { |
| CUTL_ERROR("remove " + filepath + " error, ret:" + std::to_string(ret)); |
| closedir(dir); |
| return false; |
| } |
| } |
| } |
| closedir(dir); |
| |
| |
| int ret = rmdir(dir_path.c_str()); |
| if (ret != 0) |
| { |
| CUTL_ERROR("rmdir error. dir_path:" + dir_path + ", error:" + strerror(errno)); |
| return false; |
| } |
| |
| return true; |
| } |
| } |
| |
| #endif |
7. 源码地址
更多详细代码,请查看本人写的C++ 通用工具库: common_util, 本项目已开源,代码简洁,且有详细的文档和Demo。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战