1. 程式人生 > >C++11:for_each_file遍歷目錄處理檔案

C++11:for_each_file遍歷目錄處理檔案

經常我們需要對某個目錄下的所有檔案進行處理,這裡我們需要列出目錄下的檔案,並找出符合要求的檔案,然後才開始真正的處理工作。大部分情況下,這個流程都差不多,只是檔案處理的內容不同,可不可以做一個類似#include<algorithm>中的for_each一樣的函式,把這個過程抽象化呢?
基於這個想法,實現了for_each_file函式
程式碼如下:

#include <functional>
#include <algorithm>
#include <dirent.h>
// 判斷是否是資料夾
inline bool is_folder(const
char* dir_name){ throw_if(nullptr==dir_name); auto dir =opendir(dir_name); if(dir){ closedir(dir); return true; } return false; } #ifdef _WIN32 inline char file_sepator(){ return '\\'; } #else inline char file_sepator(){ return '/'; } #endif // 判斷是否是資料夾 inline bool is_folder(const std::string &
dir_name){ throw_if(dir_name.empty()); return is_folder(dir_name.data()); } using file_filter_type=std::function<bool(const char*,const char*)>; /* * 列出指定目錄的所有檔案(不包含目錄)執行,對每個檔案執行filter過濾器, * filter返回true時將檔名全路徑加入std::vector * sub為true時為目錄遞迴 * 返回每個檔案的全路徑名 */ static std::vector<std::string>
for_each_file(const std::string&dir_name,file_filter_type filter,bool sub=false){ std::vector<std::string> v; auto dir =opendir(dir_name.data()); struct dirent *ent; if(dir){ while ((ent = readdir (dir)) != NULL) { auto p = std::string(dir_name).append({ file_sepator() }).append(ent->d_name); if(sub){ if ( 0== strcmp (ent->d_name, "..") || 0 == strcmp (ent->d_name, ".")){ continue; }else if(is_folder(p)){ auto r= for_each_file(p,filter,sub); v.insert(v.end(),r.begin(),r.end()); continue; } } if (sub||!is_folder(p))//如果是檔案,則呼叫過濾器filter if(filter(dir_name.data(),ent->d_name)) v.emplace_back(p); } closedir(dir); } return v; }

用法示例一:

const static string SUFFIX_JPG=".jpg";
const static string SUFFIX_JPEG=".jpeg";
// 字串轉小寫
inline std::string tolower(const std::string&src){
	auto dst= src;
	transform(src.begin(),src.end(),dst.begin(),::tolower);
	return dst;
}
// 判斷src是否以指定的字串(suffix)結尾
inline bool end_with(const std::string&src,const std::string &suffix){
	return src.substr(src.size()-suffix.size())==suffix;
}
//對指定的目錄下所有的jpeg影象檔案進行人臉檢測:
for_each_file("d:\\tmp\\photo",
		// filter函式,lambda表示式
		[&](const char*path,const char* name){
		auto full_path=string(path).append({file_sepator()}).append(name);
			std::string lower_name=tolower(name);
			//判斷是否為jpeg檔案
			if(end_with(lower_name,SUFFIX_JPG)||end_with(lower_name,SUFFIX_JPEG)){
				detect_face(parser,full_path);//呼叫人臉檢測函式對影象進行人臉檢測
			}
		//因為檔案已經已經在lambda表示式中處理了,
		//不需要for_each_file返回檔案列表,所以這裡返回false
		return false;
		}
		,true//遞迴子目錄
	);

用法示例二:

const static  file_filter_type default_ls_filter=[](const char*,const char*){return true;};
/*
 * 列出指定目錄的所有檔案
 * sub為true時為目錄遞迴
 * 返回每個檔案的全路徑名
 */
inline std::vector<std::string> ls(const std::string&dir_name, bool sub = false) {
	return for_each_file(dir_name, default_ls_filter, sub);
}