C++文件系统操作4 - 跨平台实现获取文件|文件夹的大小
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 56 57 58 59 60 61 62 63 64 65 66 #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_; }; uint64_t filesize (const filepath &filepath, bool link_target = false ) ; uint64_t dirsize (const filepath &dirpath) ; }
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 42 43 44 45 46 47 48 49 50 51 52 #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_; } uint64_t filesize (const filepath &filepath, bool link_target) { if (!filepath.exists ()) { CUTL_ERROR ("filepath does not exist: " + filepath.str ()); return 0 ; } return get_filesize (filepath.str (), link_target); } uint64_t dirsize (const filepath &dirpath) { return get_dirsize (dirpath.str ()); }
4. filesystem_win.h 1 2 3 4 5 6 7 8 9 10 11 12 13 #include <vector> #include <string> #pragma once namespace cutl{ uint64_t get_filesize (const std::string &filepath, bool link_target) ; uint64_t get_dirsize (const std::string &dirpath) ; }
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 #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{ uint64_t get_filesize (const std::string &filepath, bool link_target) { struct stat statbuf; int ret = stat (filepath.c_str (), &statbuf); if (ret != 0 ) { CUTL_ERROR ("stat " + filepath + " error, ret:" + std::to_string (ret)); return 0 ; } return static_cast <uint64_t >(statbuf.st_size); } uint64_t get_dirsize (const std::string &dirpath) { uint64_t totalSize = 0 ; auto findpath = dirpath + 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 totalSize; } do { auto dwAttrs = data.dwFileAttributes; auto filename = std::string (data.cFileName); if (is_special_dir (filename)) { continue ; } std::string filepath = dirpath + win_separator + filename; if ((dwAttrs & FILE_ATTRIBUTE_DIRECTORY)) { auto subdir_size = get_dirsize (filepath); totalSize += subdir_size; } else { auto subfile_size = get_filesize (filepath, false ); totalSize += subfile_size; } } while (FindNextFileA (hFind, &data)); FindClose (hFind); return totalSize; } } #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 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 122 123 124 #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{ uint64_t get_filesize (const std::string &filepath, bool link_target) { struct stat statbuf; int ret = 0 ; if (link_target) { ret = stat (filepath.c_str (), &statbuf); } else { ret = lstat (filepath.c_str (), &statbuf); } if (ret != 0 ) { CUTL_ERROR ("stat " + filepath + " error, ret:" + std::to_string (ret)); return 0 ; } return static_cast <uint64_t >(statbuf.st_size); } filetype get_file_type (int mode) { filetype type = filetype::unknown; if (S_ISBLK (mode)) { type = filetype::block_special; } else if (S_ISCHR (mode)) { type = filetype::char_special; } else if (S_ISDIR (mode)) { type = filetype::directory; } else if (S_ISFIFO (mode)) { type = filetype::pipefifo; } else if (S_ISLNK (mode)) { type = filetype::symlink; } else if (S_ISREG (mode)) { type = filetype::file; } else if (S_ISSOCK (mode)) { type = filetype::socket; } return type; } uint64_t get_dirsize (const std::string &dirpath) { uint64_t totalSize = 0 ; DIR *dir = opendir (dirpath.c_str ()); if (dir == NULL ) { CUTL_ERROR ("opendir error. dirpath:" + dirpath + ", error:" + strerror (errno)); return totalSize; } 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 totalSize; } auto ftype = get_file_type (file_stat.st_mode); if (S_ISDIR (file_stat.st_mode)) { auto subdir_size = get_dirsize (filepath); totalSize += subdir_size; } else { auto subfile_size = get_filesize (filepath, false ); totalSize += subfile_size; } } closedir (dir); return totalSize; } } #endif
7. 源码地址 更多详细代码,请查看本人写的C++ 通用工具库: common_util , 本项目已开源,代码简洁,且有详细的文档和Demo。