linux下c/c++实例之七递归扫描目录下的文件

一、简介

      Linux下递归扫描该目录下所有的文件,完成更为详细的文件操作需求。其他库中比如Qt、Boost库中已有接口函数。

二、详解

1、递归扫描文件的代码

(1)scanfile.cpp:

[html] view plain
  1. #include <iostream>  
  2. #include <string>  
  3. #include <vector>  
  4. #include <sys/stat.h>  
  5. #include <regex.h>  
  6. #include <libgen.h>  
  7. #include <dirent.h>  
  8. #include <assert.h>  
  9. #include <string.h>  
  10. #include <stdio.h>  
  11. #include <stdlib.h>  
  12. using namespace std;  
  13. vector<string> v_file;  
  14. int regex_match(const char *buffer, const char *pattern)  
  15. {  
  16.     int ret = 0;  
  17.     char errbuf[1024] = {0};  
  18.     regex_t reg;  
  19.     regmatch_t pm[1] = {0};  
  20.     ret = regcomp(&reg, pattern, REG_EXTENDED | REG_ICASE);  
  21.     if (ret != 0) {  
  22.         regerror(ret, &reg, errbuf, sizeof(errbuf));  
  23.         fprintf(stderr, "%s:regcom(%s)\n", errbuf, pattern);  
  24.         return -1;  
  25.     }  
  26.     if (regexec(&reg, buffer, 1, pm, 0) == 0) {  
  27.         regfree(&reg);  
  28.         return 0;                         //匹配成功  
  29.     }  
  30.     else {  
  31.         regfree(&reg);  
  32.         return -1;  
  33.     }  
  34. }  
  35. int scan_dirpath(char *path, char *pattern)    //递归扫描该目录下所有的文件和目录  
  36. {  
  37.     char file_path[512] = {0};  
  38.     char file[512] = {0};  
  39.     DIR *dir = NULL;  
  40.     struct dirent *ptr = NULL;  
  41.     struct stat buf;  
  42.     int i, j;  
  43.     /****************浏览目录***************************/  
  44.     if ((dir = opendir(path)) == NULL) {  
  45.         perror("opendir failed!");  
  46.         return -1;  
  47.     }  
  48.     while((ptr = readdir(dir)) != NULL) {  
  49.         if (ptr->d_name[0] != '.') {//除去根文件目录  
  50.             strcpy(file_path, path);  
  51.             if (path[strlen(path) - 1] != '/')  strcat(file_path, "/");  
  52.             strcat(file_path, ptr->d_name);          //构建完整的文件名  
  53.             assert(stat(file_path, &buf) != -1);  
  54.             if(S_ISREG(buf.st_mode)) {        //判断的是文件  
  55.                 for(i = 0; i < strlen(file_path); i++) {  
  56.                     if(file_path[i] == '/') {  
  57.                         memset(file, 0, strlen(file));  
  58.                         j = 0;  
  59.                         continue;  
  60.                     }  
  61.                     file[j++] = file_path[i];  
  62.                 }  
  63.                 if (regex_match(file, pattern) == 0) {  //正则匹配成功  
  64.                     v_file.push_back(file_path);  
  65.                 }  
  66.             }  
  67.             else if(S_ISDIR(buf.st_mode)) {   //判断的是目录  
  68.                 scan_dirpath(file_path, pattern);  
  69.             }  
  70.         }  
  71.     }  
  72.     return 0;  
  73. }  
  74.   
  75. int main()  
  76. {  
  77.     char path[512] = "/tmp/other";  
  78.     char pattern[32] = ".*.cpp";  
  79.     scan_dirpath(path, pattern);  
  80.     for (int i = 0; i < v_file.size(); i++) {  
  81.         cout<<v_file[i]<<endl;  
  82.     }  
  83.     return 0;  
  84. }  

(2)编译运行

[html] view plain
  1. g++ -o scanfile scanfile.cpp   
  2. ./scanfile  

2、非递归扫描目录文件的C++模板

(1)scanfile.cpp:
[html] view plain
  1. #include <iostream>  
  2. #include <string>  
  3. #include <vector>  
  4. #include <regex.h>  
  5. #include <assert.h>  
  6. #include <sys/stat.h>  
  7. #include <dirent.h>  
  8. #include <algorithm>  
  9. #include <unistd.h>  
  10. #include <string.h>  
  11. #include <stdlib.h>  
  12. #include <stdio.h>  
  13. using namespace std;  
  14. struct scan_info    //扫描文件信息  
  15. {  
  16.     string file_dir;  
  17.     string file_name;  
  18.     int create_time;  
  19. };  
  20. class compare_name    //lhs > rhs,get file in ascending order.  
  21. {  
  22. public:  
  23.     /*Sort by file creation time and file_name in descending order, so get file in back will be in ascending order.*/  
  24.     bool operator()(const scan_info& lhs, const scan_info& rhs) {  
  25.         if (lhs.file_name > rhs.file_name)  return true;  
  26.         //else if (lhs.create_time == rhs.create_time && lhs.file_name > rhs.file_name)  return true;  
  27.         else  return false;  
  28.     }  
  29. };  
  30. template <typename compare = compare_name>  
  31. class scan_file  
  32. {  
  33. public:  
  34.     // Scan file in single-directory mode.  
  35.     scan_file(const string& file_dir, const string& pattern, int file_count = 1024);  
  36.     // Scan file in multi-directory mode.  
  37.     scan_file(const vector<string>& dir_vector, const string& pattern, int file_count = 1024);  
  38.     // Scan file in dir/sub-dirs mode.  
  39.     scan_file(const string& dir, const vector<string>& sub_dirs, const string& pattern, int file_count = 1024);  
  40.     virtual ~scan_file();  
  41. public:  
  42.     // Get a file in given directories. Upon file found, return true, otherwise return false.  
  43.     // In single-directory mode, return file name, otherwise return full name.  
  44.     bool get_file(string& file_name);  
  45.     // Get all files in given directories.  
  46.     // In single-directory mode, return file name, otherwise return full name.  
  47.     void get_files(vector<string>& files);  
  48. private:  
  49.     vector<string> dir_vector;  
  50.     regex_t reg;  
  51.     vector<scan_info> file_vector;  
  52. };  
  53. template<typename compare> scan_file<compare>::scan_file(const string& file_dir, const string& pattern, int file_count)  
  54.     : dir_vector(1, file_dir)  
  55. {  
  56.     assert(regcomp(&reg, pattern.c_str(), REG_NOSUB | REG_EXTENDED) == 0);  
  57.     file_vector.reserve(file_count);  
  58. }  
  59. template<typename compare> scan_file<compare>::scan_file(const vector<string>& dir_vector_, const string& pattern, int file_count)  
  60.     : dir_vector(dir_vector_)  
  61. {  
  62.     // 以功能更加强大的扩展正则表达式的方式进行匹配,不用存储匹配后的结果  
  63.     assert(regcomp(&reg, pattern.c_str(), REG_NOSUB | REG_EXTENDED) == 0);  
  64.     file_vector.reserve(file_count);  
  65. }  
  66. template<typename compare> scan_file<compare>::scan_file(const string& dir, const vector<string>& sub_dirs, const string& pattern, int file_count)  
  67. {  
  68.     vector<string>::const_iterator iter;  
  69.     for (iter = sub_dirs.begin(); iter != sub_dirs.end(); ++iter) {  
  70.         dir_vector.push_back(dir + '/' + *iter);  
  71.     }  
  72.     assert(regcomp(&reg, pattern.c_str(), REG_NOSUB | REG_EXTENDED) == 0);  
  73.     file_vector.reserve(file_count);  
  74. }  
  75. template<typename compare> scan_file<compare>::~scan_file()  
  76. {  
  77.     regfree(&reg);  
  78. }  
  79. template<typename compare> bool scan_file<compare>::get_file(string& file_name)  
  80. {  
  81.     /**先扫描目录,将所有的文件都写入到vector中**/  
  82.     /**如果找到文件,每次从vector中读取一个文件**/  
  83.     /**不能递归扫描,多文件时会返回全路径**/  
  84.     DIR* dirp;  
  85.     dirent ent;  
  86.     dirent* result;  
  87.     struct stat stat_buf;  
  88.     string full_name = "";  
  89.     scan_info file_info;  
  90.     file_name = "";  
  91.     while (file_vector.size() > 0) {  
  92.         vector<scan_info>::iterator iter = file_vector.begin();  
  93.         if (access((iter->file_dir + '/' + iter->file_name).c_str(), F_OK) == -1) {  
  94.             std::pop_heap(file_vector.begin(), file_vector.end(), compare());  
  95.             file_vector.pop_back();  
  96.             continue;  
  97.         }  
  98.         if (dir_vector.size() == 1)  file_name = iter->file_name;  
  99.         else  file_name = iter->file_dir + '/' + iter->file_name;  
  100.         std::pop_heap(file_vector.begin(), file_vector.end(), compare());  
  101.         file_vector.pop_back();  
  102.         return true;  
  103.     }  
  104.     vector<string>::const_iterator dir_iter;  
  105.     for (dir_iter = dir_vector.begin(); dir_iter != dir_vector.end(); ++dir_iter) {  
  106.         assert((dirp = opendir(dir_iter->c_str())) != NULL);  
  107.         while (readdir_r(dirp, &ent, &result) == 0 && result != 0) {  
  108.             if (strcmp(ent.d_name, ".") == 0 || strcmp(ent.d_name, "..") == 0)  continue;  
  109.             if (regexec(&reg, ent.d_name, (size_t)0, 0, 0) != 0)  continue;  
  110.             full_name = *dir_iter + '/' + ent.d_name;  
  111.             assert(::lstat(full_name.c_str(), &stat_buf) >= 0);  
  112.             if (S_ISDIR(stat_buf.st_mode) == 0) {  
  113.                 file_info.file_dir = *dir_iter;  
  114.                 file_info.file_name = ent.d_name;  
  115.                 file_info.create_time = stat_buf.st_mtime;  
  116.                 file_vector.push_back(file_info);  
  117.             }  
  118.         }  
  119.         closedir(dirp);  
  120.     }  
  121.     /**也可以采用文件加载完毕后更改名字  
  122.     *err_msg << "mv " << m_real_file << " " << m_real_file << ".bak";  
  123.     *system(err_msg.str().c_str());  
  124.     **/  
  125.     if (dir_vector.size() > 0)  dir_vector.clear();  
  126.     if (file_vector.size() > 0) {  
  127.         //make_heap以迭代器[start,end] 区间内的元素生成一个堆. 默认使用元素类型 的 < 操作符 进行判断堆的类型, 因此生成的是大顶堆. 这里是小顶堆  
  128.         std::make_heap(file_vector.begin(), file_vector.end(), compare());  
  129.         while (file_vector.size() > 0) {  
  130.             vector<scan_info>::iterator iter = file_vector.begin();  
  131.             if (access((iter->file_dir + '/' + iter->file_name).c_str(), F_OK) == -1) { //文件不存在  
  132.                 //pop_heap() 并不是真的把最大(最小)的元素从堆中弹出来. 而是重新排序堆. 它把首元素和末元素交换,然后将[first,last-1]的数据再做成一个堆。  
  133.                 std::pop_heap(file_vector.begin(), file_vector.end(), compare());  
  134.                 file_vector.pop_back();  
  135.                 continue;  
  136.             }  
  137.             if (dir_vector.size() == 1)  file_name = iter->file_name;  
  138.             else  file_name = iter->file_dir + '/' + iter->file_name;  
  139.             std::pop_heap(file_vector.begin(), file_vector.end(), compare());  
  140.             file_vector.pop_back();  
  141.             return true;  
  142.         }  
  143.   
  144.         return false;  
  145.     }  
  146.     else {  
  147.         return false;  
  148.     }  
  149. }  
  150. template<typename compare> void scan_file<compare>::get_files(vector<string>& files)  
  151. {  
  152.     /**只扫描该目录下的文件,不扫描文件夹**/  
  153.     /**若想递归扫描,可将每次扫描到的文件push_back进vector**/  
  154.     DIR* dirp;  
  155.     dirent ent;  
  156.     dirent* result;  
  157.     struct stat stat_buf;  
  158.     string full_name = "";  
  159.     files.resize(0);  
  160.     vector<string>::const_iterator dir_iter;  
  161.     for (dir_iter = dir_vector.begin(); dir_iter != dir_vector.end(); ++dir_iter) {  
  162.         assert((dirp = opendir(dir_iter->c_str())) != NULL);  
  163.         while (readdir_r(dirp, &ent, &result) == 0 && result != 0) {  
  164.             if (strcmp(ent.d_name, ".") == 0 || strcmp(ent.d_name, "..") == 0)  continue;  
  165.             full_name = *dir_iter + '/' + ent.d_name;  
  166.             if (regexec(&reg, ent.d_name, (size_t)0, 0, 0) != 0)  continue;  
  167.             assert(::lstat(full_name.c_str(), &stat_buf) >= 0);  
  168.             if (S_ISDIR(stat_buf.st_mode) == 0) {        //不是文件夹  
  169.                 if (regexec(&reg, ent.d_name, (size_t)0, 0, 0) == 0) {  
  170.                     files.push_back(ent.d_name);  
  171.                 }  
  172.             }  
  173.         }  
  174.         closedir(dirp);  
  175.     }  
  176. }  
  177. int main()  
  178. {  
  179.     string path = "/tmp/other";  
  180.     string pattern = ".*.cpp";  
  181.     scan_file<> *tmp = new scan_file<>(path, pattern, 1);  
  182.     /**********方式一:单个文件获取************/  
  183.     string file = "";  
  184.     while (tmp->get_file(file) == true) {  
  185.         cout<<file<<endl;  
  186.     }  
  187.     delete tmp;  
  188.     /**********方式二:vecotor获取************/  
  189.     cout<<"------------------------------------"<<endl;  
  190.     tmp = new scan_file<>(path, pattern, 1);  
  191.     vector<string> files;  
  192.     tmp->get_files(files);  
  193.     vector<string>::iterator it;  
  194.     for ( it = files.begin(); it < files.end(); it++ ) {  
  195.         cout<<*it<<endl;  
  196.     }  
  197.     delete tmp;  
  198.     return 0;  
  199. }  
(2)编译运行:
[html] view plain
  1. g++ -o scanfile scanfile.cpp   
  2. ./scanfile  

三、总结

(1)递归扫描路径暂只能使用绝对路径,相对路径需要自己转换。
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页