나는 scandir
또는 관련 C 기능에 대한 사전 지식이 없다는 것을 인정해야합니다. 그러나 내가 읽은 내용을 <dirent.h>
에있는 문서를 통해 이해하면 저수준 APIS로 여러 호출을 래핑하는 도우미 함수입니다.
이러한 경우 나는 C++과 같은 기능을 가진 동일한 기능을 구현하는 C++ 래퍼를 만드는 것을 선호합니다. 이 같은
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;
}
과 같이 호출 제대로 정리되었는지 확인하기 위해 DIR
유형의 래퍼로 시작
이 :
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()
은 스레드로부터 안전하지 않은 구현을 만듭니다.하지만 더 많은 검사가 추가되어 오류에 의해 반환 된 오류를보고해야합니다.
참고 :
void with_file_names(const std::string &path,
std::function<void(const std::string& name)> action,
int(*filter)(const struct dirent *) = NULL)
{
struct dirent **namelist;
auto nfiles = scandir(path.c_str(),
&namelist,
filter,
NULL);
for (auto idx = 0; idx < nfiles; idx++)
{
auto n = namelist[idx];
action(std::string(n->d_name, n->d_namlen));
}
free(namelist);
}
다음
with_file_names("./downloaded",
[](const std::string &file_name){
auto fullname = std::string("./downloaded/") + file_name;
// do something...
},
[](const struct dirent *pentry) {
return (int)(::strncmp("node-", pentry->d_name, 5) == 0);
});
통지 필터 매개 변수를 :
#include <dirent.h>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <stdexcept>
#include <vector>
질문의 요점을 놓쳤다 고 생각합니다. 람다 함수를 사용하여 필터 함수에 인수를 전달할 수는 없으므로, 실제로 도움이되지 않습니다. –
@ Étienne 그것은 재미 있습니다. 왜냐하면 _almost_가 도움이되기 때문입니다. 그는 비 캡처 람다 (실제로는 함수 포인터로 변환 될 수 있기 때문에 'scandir'의 이론적으로 유효한 피연산자입니다)를 사용하지만 대담 자로'std :: function'을 사용합니다 그 가능성을 완전히 없애 버린다. 'std :: function'을'std :: add_pointer_t' ('type_traits')로 변경하면 실제로 작동 할 수 있습니다 ('scandir '과 비슷한 것을 얻었습니다). – fish2000
수정 된 버전의 FileZilla에서 사용 했으므로 설명대로 작동합니다. –