C++11:for_each_file遍历目录处理文件

2019-05-25 22:03:07 浏览数 (1)

版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433581

经常我们需要对某个目录下的所有文件进行处理,这里我们需要列出目录下的文件,并找出符合要求的文件,然后才开始真正的处理工作。大部分情况下,这个流程都差不多,只是文件处理的内容不同,可不可以做一个类似#include<algorithm>中的for_each一样的函数,把这个过程抽象化呢?

基于这个想法,实现了for_each_file函数

代码如下:

代码语言:javascript复制
#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;
}

用法示例一:

代码语言:javascript复制
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//递归子目录
	);

用法示例二:

代码语言:javascript复制
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);
}

0 人点赞