我不得不承认我以前没有scandir
任何相关的 C 函数的知识。但是根据我通过阅读有关文档的理解,<dirent.h>
它是一个辅助函数,它包装了对较低级别 APIS 的多次调用。
在这种情况下,我更喜欢创建一个实现相同功能的 C++ 包装器,并使用类似 C++ 的 API。
从类型周围的包装器开始,DIR
以确保正确清理它:
namespace cpp {
struct DIR {
::DIR * dir;
DIR(const std::string & path) : dir(opendir(path.c_str()))
{
if(dir==0) throw std::runtime_error("Unable to open path");
}
~DIR() { if(dir!=0) closedir(dir); }
operator ::DIR * () { return dir; }
};
}
该scandir
功能现在可以实现如下:
template<class Filter, class Compare>
std::vector<dirent> scandir(const std::string & path, const Filter& filter, const Compare& compare) {
cpp::DIR dir(path);
std::vector<dirent> res;
dirent entry, *entry_ptr = &entry;
while( ::readdir_r(dir, &entry, &entry_ptr)==0 ) {
if( entry_ptr==0 ) break;
if( filter(entry) ) res.push_back(entry);
}
std::sort(begin(res), end(res), compare);
return res;
}
并这样称呼它:
std::string path = ...;
...
auto filter = [] (const dirent& entry) { return entry.d_name[0]!='.'; };
auto compare = [](const dirent & lhs, const dirent & rhs) {
return std::strcmp(lhs.d_name, rhs.d_name)<0;
};
auto entries = cpp::scandir(path, filter, compare);
的使用readdir_r()
使得上面的实现是线程安全的,尽管应该添加更多的检查来报告它返回的任何错误。
注意:上面的代码需要包含以下标头:
#include <dirent.h>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <stdexcept>
#include <vector>